Cybersecurity moves fast, and IT professionals constantly seek ways to improve productivity and efficiency. This guide focuses on automation using PowerShell, one of today’s most powerful and popular scripting languages. It will provide an understanding of the fundamentals, tool capabilities, and best practices for automating repetitive tasks using PowerShell.
What is PowerShell?
PowerShell is a task automation and configuration management framework developed by Microsoft. It is a scripting language and an interactive command-line shell designed to simplify system management tasks.
Foundations of using PowerShell
To master PowerShell, it is important to grasp fundamental concepts like cmdlets (pronounced “command-lets”), which are lightweight commands used in PowerShell, and pipelines, which allow data to pass between cmdlets.
A PowerShell script is a series of commands and instructions written in the PowerShell scripting language. It allows the automation of complex tasks by executing multiple commands in sequence.
Simple PowerShell scripts for automation
PowerShell scripts are a powerful tool for automation. They can streamline repetitive tasks, reduce human error, and save valuable time and resources.
Common PowerShell tasks and their scripts
User provisioning and management
# Create a new user New-ADUser -Name "James Roberts" -SamAccountName "jamesroberts" -UserPrincipalName "jamesroberts at domain.com" -AccountPassword (ConvertTo-SecureString "ChangeMe123" -AsPlainText -Force)
File and folder operations
# Copy files from one folder to another $sourceFolder = "C:source" $destinationFolder = "D:destination" Copy-Item -Path "$sourceFolder*" -Destination $destinationFolder -Recurse
Explanation: This script copies all files from the source folder to the destination folder, including subdirectories (recursively).
System CPU monitoring and reporting
# Get CPU usage
$cpuUsage = Get-Counter -Counter "Processor(_Total)% Processor Time"
$cpuUsage.CounterSamples | ForEach-Object { Write-Host "Processor: $($_.InstanceName), Usage: $($_.CookedValue)%"
}Explanation: This script retrieves CPU usage information for all processors and displays the usage percentage for each.
You may also be interested in our article on How to Lower CPU Usage.
Security-related tasks
# Check open ports on a remote host
$hostname = "example.com"
$ports = 80, 443, 22
$ports | ForEach-Object { $port = $_ $result = Test-NetConnection -ComputerName $hostname -Port $port if ($result.TcpTestSucceeded) { Write-Host "Port $port is open" } else { Write-Host "Port $port is closed" }
}Explanation: This script tests the availability of specific ports on a remote host and reports whether each port is open or closed.
Network configuration
# Configure a network adapter with a static IP address $interfaceName = "Ethernet" $ipAddress = "192.168.1.100" $subnetMask = "255.255.255.0" $gateway = "192.168.1.1" $dnsServers = "8.8.8.8", "8.8.4.4" Set-NetIPAddress -InterfaceAlias $interfaceName -IPAddress $ipAddress -PrefixLength 24 -DefaultGateway $gateway Set-DnsClientServerAddress -InterfaceAlias $interfaceName -ServerAddresses $dnsServers
Explanation: This script configures a network adapter with a static IP address, subnet mask, default gateway, and DNS server addresses.
PowerShell automation of complex tasks
Continuous log monitoring and alerting
# Monitor a log file and send an email alert on a specific event
$logFilePath = "C:logsapp.log"
$keywordToMonitor = "ERROR"
$recipientEmail = "admin at domain.com"
$smtpServer = "smtp.domain.com"
$smtpPort = 587
Get-Content -Path $logFilePath -Wait | ForEach-Object { if ($_ -match $keywordToMonitor) { Send-MailMessage -From "alerts at domain.com" -To $recipientEmail -Subject "Error Alert" -SmtpServer $smtpServer -Port $smtpPort }
}Explanation: This script continuously monitors a log file for an error condition, using the occurrence of a specific keyword (“ERROR”), then sends an email alert when it detects that keyword.
Log analysis and reporting
# Analyze log files and generate a report
$logFiles = Get-ChildItem -Path "C:logs" -Filter "*.log" -File
$results = @()
foreach ($logFile in $logFiles) { $logContent = Get-Content -Path $logFile.FullName $errorCount = ($logContent | Select-String -Pattern "ERROR").Count $results += [PSCustomObject]@{ LogFileName = $logFile.Name ErrorCount = $errorCount }
}
$results | Export-Csv -Path "log_analysis.csv" -NoTypeInformationExplanation: This script scans a directory for log files, analyzes each log file to count the occurrences of the “ERROR” keyword, and generates a CSV report with the log file names and error counts.
You might also be interested in our article on Linux Log Management: Advanced Techniques and Best Practices.
Integration with third-party APIs
# Interact with a REST API to retrieve data
$apiUrl = "https://api.example.com/data"
$headers = @{ "Authorization" = "Bearer YourAuthToken"
}
$response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Get
# Process the response data
if ($response.StatusCode -eq 200) { $data = $response | ConvertFrom-Json Write-Host "Received data from the API:" $data | Format-Table
} else { Write-Host "Failed to retrieve data from the API. Status code: $($response.StatusCode)"
}Explanation: This script interacts with a REST API by sending an authenticated GET request, processes the API response, and displays the received data.
Complex data manipulation
# Transform and aggregate data from multiple sources
$data1 = Import-Csv -Path "source1.csv"
$data2 = Import-Csv -Path "source2.csv"
# Merge data from different sources
$mergedData = $data1 | ForEach-Object { $item1 = $_ $matchingItem = $data2 | Where-Object { $_.ID -eq $item1.ID } if ($matchingItem) { $_ | Select-Object *, @{Name="AdditionalProperty";Expression={$matchingItem.Property}} } else { $_ }
}
# Export the merged data
$mergedData | Export-Csv -Path "merged_data.csv" -NoTypeInformationExplanation: This script imports data from two CSV files, merges them based on a common ID, and exports the merged data to a new CSV file.
Case studies of real-world automation tasks solved with PowerShell
To provide practical insights into the power of PowerShell, we’ll look at two real-world scenarios where PowerShell automation has been applied to solve complex tasks.
Case study #1: Active Directory user account management
Solution: PowerShell was used to automate these tasks. Scripted tasks included:
- Creating new user accounts: A PowerShell script was created to read user information from a CSV file and automatically create new user accounts in Active Directory with appropriate attributes like username, password, and group memberships.
- Disabling or deleting inactive user accounts: Another script was developed to identify and disable or delete user accounts for employees who were no longer with the company based on the last login date. This script regularly checked user activity and performed the necessary actions.
- User attribute updates: PowerShell scripts were scheduled to run at specific intervals to update user attributes such as job titles, department, and contact information based on data from the HR system.
Case study #2: Patch management
Solution: PowerShell automation was implemented to streamline patch management:
These examples demonstrate how PowerShell can be a powerful tool for automating routine and time-consuming tasks in real-world IT environments, leading to improved efficiency, accuracy, and security. Real-world scenarios may involve more complex automation scripts and considerations. The actual implementation can vary based on specific requirements and organizational needs.
Learn how NinjaOne can automate patch management for any endpoint.
PowerShell scripting best practices
Use PowerShell execution policies
Set PowerShell execution policies to restrict the execution of scripts to trusted sources. For example, set the execution policy to “RemoteSigned” or “AllSigned” to ensure that only signed scripts or scripts from trusted locations can run.
Use digital signatures
Digitally signing PowerShell scripts with a code-signing certificate adds an extra layer of security. It ensures that the script has not been tampered with since it was signed. PowerShell can verify the digital signature to confirm its authenticity when executing scripts.
Follow the principle of least privilege
Store credentials securely
Use input validation
Implement error handling
Robust error handling in scripts allows them to handle unexpected situations gracefully. Avoid displaying sensitive information in error messages that attackers could exploit.
Use secure protocols
When connecting to remote systems or web services, use secure protocols such as HTTPS or SSH. Avoid sending sensitive information over unencrypted connections.
Regularly update and patch
Keep PowerShell and any modules or dependencies up to date with the latest security patches and updates. Outdated software can be vulnerable to known exploits.
Log and audit
Implement logging and auditing mechanisms to track script execution and detect suspicious activities. PowerShell’s Start-Transcript cmdlet can be useful for this purpose.
Perform regular code reviews
Conduct regular code reviews of PowerShell scripts to identify potential security vulnerabilities. Consider using code analysis tools to automate this process.
Follow industry recommendations
Stay informed about industry-specific security recommendations and compliance requirements (e.g., PCI DSS, HIPAA, GDPR) that apply to your organization. Ensure that any scripts developed align with these standards.
Automation strategy drives efficiency
In the ever-evolving landscape of cyber security and IT management, a well-executed PowerShell automation strategy is not just a tool; it’s a game-changer. This strategy empowers IT professionals to optimize business operations, achieve scalability, fortify their cyber security posture, and retain the flexibility needed to thrive in the digital age.
When you’re ready to take your automation strategy to the next level, consider NinjaOne’s IT automation tools to enable automated patching, software installations or remediation actions based on reaching condition thresholds, according to your defined schedule, or ad hoc. Embed automated responses into your device and group policies always retaining the ability to override or change policies as needed.
PowerShell scripts are a great way to automate daily tasks or generate weekly reports. But how do you make a scheduled task for your PowerShell scripts? We can do this with either the task scheduler to run a PowerShell script or create the task in PowerShell.
The advantage of scheduled tasks is that you can set and forget them. They will run in the background, and update your systems, or generate the reports that you otherwise will have to do manually.
In this article
In this article, we will look at how to run a PowerShell script with task scheduler and how to create a scheduled task in PowerShell.
Use Task Scheduler to Run a PowerShell Script
The first option that we are going to look at is using the task scheduler in Windows to run a PowerShell Script. The Windows Task Scheduler originates from Windows 95! and is a great way to schedule tasks in Windows.
To run PowerShell scripts with the task scheduler, we can’t simply select the PowerShell file that we want to schedule. What we are going to do is run the “program” PowerShell and use the arguments to select the file that we want to run.
2 minutes
- Open Task Scheduler
- Create a new basic task

- Schedule the task
The trigger determines when the task should be executed. Choose a trigger, for example, Weekly, and click Next to configure when exactly the tasks need to be executed.
- Set the Action
Here comes the important part, for the action, we are going to Start a Program

- Start a Program – PowerShell
The program that we want to run is PowerShell. Just enter PowerShell in the Program/Script field (see screenshot in step 6), you don’t need to find the exact path to the executable.
- Add Arguments
In the arguments field, we are going to add the argument
-Fileand path to the PowerShell script. It’s also a good idea to add the PowerShell switch-NoProfileand set the-ExecutionPolicyto ByPass.If your scripts require any parameters then you can add them after the path (for example the -Output parameter):
-NoProfile -ExecutionPolicy Bypass -File "C:\scripts\ADHealth.ps1" -Output "HTML"
- Start in
Always set the Start in location to the same path as where your script is located. This way any exports that your script generates will be stored in the same location as your script. Otherwise, the output will be saved in C:\Windows\System32
- Finish

- Advanced Settings
There are two settings that we need to change for our scheduled PowerShell task. We will need to make sure that the script runs even when we are not logged on, which you do on the General tab.

- Save the task
Click Ok and enter your password, so the task can run when you are not logged on. It is always a good idea to test your task, right-click on it, and choose Run to run the task now.
We can of course also use PowerShell to create and manage scheduled tasks. Creating a scheduled task in PowerShell requires a couple of steps. For each step, there is a different cmdlet that we are going to use.
| Cmdlet | Description |
|---|---|
| New-ScheduledTaskTrigger | Creates a trigger object for a scheduled task |
| New-ScheduledTaskAction | Creates the action for a scheduled task |
| Register-ScheduledTask | Registers a scheduled task |
| Get-ScheduledTask | Show the scheduled tasks |
$taskTrigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Friday -At 3am $taskAction = New-ScheduledTaskAction -Execute "PowerShell" -Argument "-NoProfile -ExecutionPolicy Bypass -File 'C:\scripts\ADHealth.ps1' -Output 'HTML'" -WorkingDirectory 'c:\scripts' Register-ScheduledTask 'Lazy PS Tasks' -Action $taskAction -Trigger $taskTrigger
This will create the exact same task that we have created with the task scheduler. But let’s explain each of the cmdlets to see what options we have.
Creating the Trigger – New-ScheduledTaskTrigger
The first step is to define the trigger. This determines when we want to run the task. Just like with the task scheduler, we can define multiple triggers for our task.
The New-ScheduledTaskTrigger cmdlet comes with a couple of parameters that allow you to define when you want to task to run:
- AtLogOn – Runs the task when a user logs on
- AtStartup – When the system is started
- At – Used with Once, Daily, or Weekly. Defines the specific time to run the task
- Daily – Runs every day. Define the days with DaysOfWeek
- DaysInterval – Run every x days
- DaysOfWeek – This can be used with Daily or Weekly. Defines which days to run the task
- Weekly – Runs the tasks every week
- WeeklyInterval – Determines the interval between the weeks.
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Tuesday,Thursday -At 8:30am
Defining the Action – New-ScheduledTaskAction
To create the scheduled task action in PowerShell we will need to define which program we want it to run, any arguments (the path to the PowerShell scripts for example), and optionally the working directory.
So to run our PowerShell script we will set the -Execute parameter to PowerShell and define the file path and other parameters in the -Argument parameter. If your scripts require it, you can set the –WorkingDirectory parameter to the path of your script
$action = New-ScheduledTaskAction -Execute 'PowerShell' -Argument '-NoProfile -ExecutionPolicy Bypass -File "C:\scripts\ADHealth.ps1" -Output "HTML"'
Creating the Task – Register-ScheduledTask
With the trigger and action defined, we can create and register the scheduled task. We will need to give our task a name and I recommend adding a TaskPath (folder) as well. This will make it easier to retrieve your tasks later on.
Register-ScheduledTask -TaskName 'Lazy PS Tasks' -TaskPath 'LazyTasks' -Action $taskAction -Trigger $taskTrigger

As mentioned you can define multiple triggers and actions for your task. To do this you will need to add the trigger or actions in an array. For example, to run the task every Tuesday and Thursday and on the first day of the month we can do:
# Define the triggers for Tuesday and Thursday at 08:30 AM and when a user logs on $taskTriggers = @( New-ScheduledTaskTrigger -Weekly -DaysOfWeek Tuesday,Thursday -At 08:30, New-ScheduledTaskTrigger -AtLogon ) Register-ScheduledTask -TaskName 'Lazy PS Tasks' -TaskPath 'LazyTasks' -Action $taskAction -Trigger $taskTriggers
Running the Task with Different Privileges
Register-ScheduledTask -TaskName "Lazy PowerShell Tasks" -taskPath 'LazyTasks' -Action $taskAction -Trigger $taskTrigger -User "lazyadmin\Administrator" -Password 'yourPass123' -RunLevel Highest
View the Scheduled Task
You can view your created tasks in the task scheduler. But you can also retrieve the scheduled task with PowerShell. For this, we will need to use the cmdlet Get-ScheduledTask. If you run the cmdlet without any parameters, then it will retrieve all scheduled tasks on your computer.
And as you can see, that is quite a lot. That’s why it’s important to organize your tasks in folders by using the taskPath parameter. This way you can use the TaskPath parameter to view only our tasks:
Get-ScheduledTask -TaskPath \LazyTasks\
The task path always starts and ends with a backslash \. To view your tasks you will need to supply the TaskName. If the name is unique, then the name alone will be enough. Otherwise, you will need to supply the path as well:
Get-ScheduledTask -TaskName 'Lazy PS Tasks' -TaskPath \LazyTasks\ | Select *
As you can see in the screenshot above, we can’t see all the details of the task. To view the Actions or Triggers we will need to expand the properties. We can do this by using the ExpandProperty method or by saving the results in a variable:
Get-ScheduledTask -TaskName 'Lazy PS Tasks' -TaskPath \LazyTasks\ | Select -ExpandProperty Triggers # Or $task = Get-ScheduledTask -TaskName 'Lazy PS Tasks' -TaskPath \LazyTasks\ $task.Triggers
Updating Tasks
To update scheduled tasks with PowerShell you can use the Set-ScheduledTask cmdlet. It works similar to the Register-ScheduledTask cmdlet. Just create a new trigger or action first and then add it just like when you would create it.
# Define new trigger $newTrigger= New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 08:30 # Update the task Set-ScheduledTask -TaskName "Lazy PowerShell Tasks" -taskPath 'LazyTasks'-Trigger $newTrigger
Wrapping Up
Scheduling PowerShell Tasks can be done with both Task Scheduler and in PowerShell with the Register-ScheduledTask cmdlet. Personally, I find it easier to create the task using PowerShell, but to modify it, I find the task scheduler more convenient.
Nevertheless, you can use both options to schedule your PowerShell scripts. I hope you found this article helpful, if you have any questions, just drop a comment below.
Since yesterday I noticed a significant performance degradation in executing some tasks in my pipeline that run PowerShell scripts, something that used to take a second or less now takes about 30 seconds.
No changes were made to the script within the task, and looking at the timeline from the logs the script executes at the same speed as before, what’s seems to be taking longer is loading the task itself.
See the time it takes in the log below to the ‘Generating script’
2023-09-22T11:37:41.8526876Z ##[section]Starting: Get latest build id
2023-09-22T11:37:41.8656716Z ==============================================================================
2023-09-22T11:37:41.8656891Z Task : PowerShell
2023-09-22T11:37:41.8656960Z Description : Run a PowerShell script on Linux, macOS, or Windows
2023-09-22T11:37:41.8657094Z Version : 2.228.0
2023-09-22T11:37:41.8657162Z Author : Microsoft Corporation
2023-09-22T11:37:41.8657247Z Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell
2023-09-22T11:37:41.8657393Z ==============================================================================
2023-09-22T11:38:19.5788471Z Generating script.
2023-09-22T11:38:21.4712306Z ========================== Starting Command Output ===========================
2023-09-22T11:38:21.4999099Z ##[command]"C:\Program Files\PowerShell\7\pwsh.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'D:\a\_temp\29d29486-b5d7-4487-be00-e0187e860ff8.ps1'"
2023-09-22T11:38:29.5517463Z Resolve PAT
2023-09-22T11:38:32.0041258Z Get definitionid
2023-09-22T11:38:32.0048080Z https://dev.azure.com/mycompany/myapp/_apis/build/definitions?name=CreditReference&api-version=7.1-preview.7
2023-09-22T11:38:56.9989185Z definitionId: 9668
2023-09-22T11:38:57.0015076Z https://dev.azure.com/mycompany/myapp/_apis/build/builds?definitions=9668&resultFilter=succeeded&api-version=7.1-preview.7
2023-09-22T11:38:57.9464070Z Found 1 versions
2023-09-22T11:38:57.9544224Z 245699 - 4/21/2023 8:20:05 AM
2023-09-22T11:39:02.8780176Z ##[section]Finishing: Get latest build idAnd compare this to the one from a couple of days ago:
2023-09-20T11:03:43.2781737Z ##[section]Starting: Get latest build id
2023-09-20T11:03:43.3036843Z ==============================================================================
2023-09-20T11:03:43.3036985Z Task : PowerShell
2023-09-20T11:03:43.3037045Z Description : Run a PowerShell script on Linux, macOS, or Windows
2023-09-20T11:03:43.3037135Z Version : 2.226.2
2023-09-20T11:03:43.3037189Z Author : Microsoft Corporation
2023-09-20T11:03:43.3037261Z Help : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell
2023-09-20T11:03:43.3037360Z ==============================================================================
2023-09-20T11:03:45.1817132Z Generating script.BTW, changing the script to execute with Powershell Core instead of Powershell has improved slightly the time it takes to execute but is still significantly slower.
Windows PowerShell scripts can be used to automate all manner of tasks within a Windows environment. However, for these automations to be truly useful, you may need to schedule them.
In my own organization, for example, I use PowerShell scripts to monitor storage array health, Hyper-V replication, and more. I also use a script that creates file-level backups of my unstructured data. While these scripts can be manually executed, it is far more practical to run them on a scheduled basis. That way, you don’t need to remember to run them.
Steps for Using Windows Task Scheduler
The Windows Task Scheduler can schedule the execution of PowerShell scripts at specified times. Although the process of scheduling a PowerShell script isn’t overly complex, it may not be nearly as intuitive as you might assume. To illustrate this, let’s look at the steps for in creating a scheduled task that is not directly related to PowerShell.
Open Task Scheduler and right-click on Task Scheduler Library. From the shortcut menu, select “Create Basic Task” to launch the Create Basic Task Wizard.
On the initial screen of the wizard, enter a name and a description for the task you are creating. Having meaningful names and descriptions is helpful when managing multiple tasks over time.
Click Next to go to a screen that asks you when you want the task to start. As you can see in Figure 1, you can choose from options like daily, weekly, monthly, at computer startup, when a specific event is logged, and when you log in. You can also opt to run the task only once.

Task Scheduler 1
Choose when you want to run the task.
After making your selection, click Next. You will go to a screen where you can specify the schedule for the task to occur. The options on this screen may vary based on your previous selection, but typically, you will enter a start date and time for the task.
When you are done setting the schedule, click Next again. You will see a screen that asks what should happen at the scheduled time. For example, you can start a program, send an email, or display a message. Since we are discussing PowerShell in this case, choose the “Start a Program” option and click Next.
On the next screen, you will see a field like the one shown in Figure 2. Here, you should enter the path and filename of the program that you want to launch (in this case, the PowerShell executable), along with any necessary command line arguments. Once you have provided this information, click Next, and then Finish to create the scheduled task.

Task Scheduler 2
Enter the path to the executable that you want to run.
Executing PowerShell Scripts With Task Scheduler
As straightforward as creating a scheduled task may seem, you can’t simply enter the path and filename of a PowerShell script directly. If you do so, the task will likely open the script for editing (depending on your computer’s configuration) and won’t execute the script.
This happens because Task Scheduler operates similarly to the Windows Run prompt. Since the Windows Run prompt links to the Windows Command environment, not to PowerShell, you can’t just enter the name of a PowerShell script into the Run prompt and expect it to execute.
The trick to solving this problem is to use the “Start a Program” interface shown in the figure above to launch PowerShell itself, not your PowerShell script. As you may recall in Step 6, this interface allows you to enter command line arguments, and, fortunately, PowerShell.exe just happens to accept a particular argument called File. Using the File argument, you can specify the path and filename of the PowerShell script you want to execute. Additionally, if you want the script to remain visible on screen while running, you can also use the NoExit argument. You can see an example of what this looks like in Figure 3.

Task Scheduler 3
This is how you schedule a PowerShell script to run automatically.
About the Author(s)

Brien Posey is a bestselling technology author, a speaker, and a 20X Microsoft MVP. In addition to his ongoing work in IT, Posey has spent the last several years training as a commercial astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space.
I am writing a basic powershell task, in a task template, that does something rather simple. Reads a variable (for testing purposes set to True) and evaluates it in an if/else statement. The variable candeploy is set in a variable template, other than the template where the task is defined.
- powershell: | if($(candeploy) -eq $true) { write-host This should run when true - $(candeploy) } else { write-host This should run when false - $(candeploy) } displayName: Verify Start Parameters #condition: eq( variables.candeploy, true ) failOnStderr: true errorActionPreference: stopThough $(candeploy) is always true the if statement always results to false.
Result of running task.
What am I missing? Thanks.
asked Nov 23, 2023 at 23:19
I found it very interesting that both environment variable and single/double quoted macro syntax worked.
variables:
- name: candeploy value: True
steps:
- powershell: | if( $env:CANDEPLOY -eq $true) { write-host This should run when true - $(candeploy) } else { write-host This should run when false - $(candeploy) } displayName: Verify Start Parameters - Env Var failOnStderr: true errorActionPreference: stop
- powershell: | if( '$(CANDEPLOY)' -eq $true) { write-host This should run when true - $(candeploy) } else { write-host This should run when false - $(candeploy) } displayName: Verify Start Parameters - Single Quoted Macro Syntax failOnStderr: true errorActionPreference: stop
- powershell: | if( "$(CANDEPLOY)" -eq $true) { write-host This should run when true - $(candeploy) } else { write-host This should run when false - $(candeploy) } displayName: Verify Start Parameters - Double Quoted Macro Syntax failOnStderr: true errorActionPreference: stop
I think this is because variables with macro syntax get processed before a task executes during runtime. When the system encounters a macro expression, it replaces the expression with the contents of the variable.
Here are the differences in the script from the debug logs.

Hope the suggestion would work for you as well.
answered Nov 24, 2023 at 3:08

I think you should not set variable with the type of bool, variable should be only string type in azure devop yaml. “All variables are strings and are mutable. The value of a variable can change from run to run or job to job of your pipeline.”
below is my sample code for testing (with variable type string not boolean), hope this can help.
Note: be caution of the variable only pass the pure string, not with
quotes.
pool: vmImage: windows-latest
variables: candeploy: 'true'
steps:
- powershell: | write-host "test 1 candeploy is: $(candeploy)" if($(candeploy) -eq 'true') { write-host This should run when true - $(candeploy) } else { write-host This should run when false - not $(candeploy) } displayName: Verify variables 1
- powershell: | write-host "test 1 candeploy is: $(candeploy)" if('$(candeploy)' -eq 'true') { write-host This should run when true - $(candeploy) } else { write-host This should run when false - not $(candeploy) } displayName: Verify variables 2

answered Nov 28, 2023 at 3:16

1 gold badge6 silver badges9 bronze badges
Practical Graph: Creating and Updating Planner Tasks
Learning to Create and Update Tasks in a Planner Plan Using PowerShell

Synchronization 101
The basic idea is:
- Define a target plan.
- Find new announcement items.
- Create new tasks for the announcement items in the target plan.
I wanted to give my version of the synchronization some bells and whistles that the standard version doesn’t support, so I added:
- Automatic assignment of tasks to designated team members.
- Automatic update of tasks with labels (Planner supports up to 25 different labels per plan).
- Add a target date for each task.
Let’s see how these steps unfold.
Defining a Target Plan
To make things simple, the script defines two variables for the target group and plan. The target group (which owns the plan) is defined by its group identifier. The target plan is defined by its display name:
$GroupId = '78b47932-b35f-4b26-94c2-3228cb234b07' $TargetPlanName = 'Admin Task Assignment'
Finding New Microsoft 365 Message Center Notifications
Message center notifications are called service announcement messages, part of the service health and communications Graph API. The SDK cmdlet to retrieve service announcement messages is Get-MgServiceAnnouncementMessage. Another example of using this cmdlet is to figure out how many announcements made by Microsoft end up being delayed for one reason or another.
This code shows how the script fetches service announcements and then filters the items to find those with a start date greater than the check date. Logically, to make sure that synchronization works as it should, the check date should be the date of the last run.
[array]$AllAnnouncements = Get-MgServiceAnnouncementMessage -Sort 'LastmodifiedDateTime desc' -All
[array]$AnnouncementsForPeriod = $AllAnnouncements | Where-Object {$_.StartDateTime -as [datetime] -gt $CheckDate}
If ($AnnouncementsForPeriod.Count -eq 0) { Write-Host ("No new message center posts found since {0} - exiting" -f $CheckDate) Break
} Else { Write-Host ("{0} message center posts found to process..." -f $AnnouncementsForPeriod.count)
}The next step in the script creates or updates tasks. We’ll come back to how that happens soon.

Automatic Assignment to Plan Members
$SharePointAssignee = $PlanMembers.additionalProperties | Where-Object mail -match 'Rene.artois@office365itpros.com' $SharePointAssignee = (Get-MgUser -UserId $SharePointAssignee.userPrincipalName) | Select-Object -First 1
Automatic Assignment of Labels
As mentioned earlier, a plan can use up to 25 labels. Each label has a color and an assigned display name (by default, the color) that can be customized for use within a plan. When the standard synchronization runs, it does not assign a label to the tasks it creates. Before the script can do so, someone needs to define the labels (easily done in the create task dialog) and we need to include details about the labels in the script.
The Planner GUI only shows labels with whatever customized names are set up for a plan. To discover the label numbers, we need to example the categoryDescriptions setting for the plan. Here’s how to find this information:
$Uri =("https://graph.microsoft.com/beta/planner/plans/{0}/details" -f $TargetPlan.id)
$Data = Invoke-MgGraphRequest -Uri $Uri -Method GET
$Data.Categorydescriptions
Name Value
---- -----
category17 Microsoft Viva
category7 SharePoint Online
category6 Microsoft 365 AppsBefore the script can create a new task, several hash tables must be populated with the settings for the new task. The script uses hash tables for:
- Task parameters.
- Assignments.
- Labels.
- Description (the body of the task holding a free-text description about the task details). The script does some processing to remove HTML tags from the body included in a service announcement. It also adds some details to the top of the description that appear in tasks created by the regular synchronization. These details include the message center identifier (for example, MC712150), dates for publication and last update, categories, and tags (Figure 1).

Creating a new task is done by running the New-MgPlannerTask cmdlet. All the parameters for the new task are specified in a hash table. Here’s the snippet of code covering the creation of a new task.
$TaskParameters = @{} $TaskParameters.Add('planId',$TargetPlan.Id) $TaskParameters.Add('bucketid',$TargetBucket) $TaskParameters.Add('title', $TaskTitle) $TaskParameters.Add('assignments', $TaskAssignments) $TaskParameters.Add('priority', '5') $TaskParameters.Add('startDateTime', $Announcement.LastModifiedDateTime) $TaskParameters.Add('details',$TaskDescription) $TaskParameters.Add('appliedCategories', $TaskLabels) # If an end date is given, use it as the due date for the task If ($Announcement.EndDateTime) { $TaskParameters.Add('dueDateTime', $Announcement.EndDateTime) } $NewTask = New-MgPlannerTask -BodyParameter $TaskParametersWhen Planner detects the creation of a new task, it automatically sends email to the task assignees to tell them that they have a new task (Figure 2). The same happens for tasks created using the Planner browser app and Tasks in Teams. It doesn’t happen when the Planner mobile app creates new tasks.

Updating Previously Assigned Tasks
The script also includes code to handle updates for previously assigned tasks. This is done by comparing the set of uncompleted tasks in the plan (retrieved with the Get-MgPlannerPlanTask cmdlet) against the set of service announcements that is stored between runs of the script in a CSV file. If an update is found, the script updates the task using the Update-MgPlannerTask cmdlet. If necessary, the task description is updated using the the Update-MgPlannerTaskDetail cmdlet.
The last thing that the script does is to export the set of service announcements to the CSV file in preparation for the next run. In truth, synchronization of updates against existing tasks is the code that I have the least confidence in because I didn’t spend as much time working on it. Consider it a challenge to check and improve the code if you have the time and interest.
Getting and Running the Script
Figure 3 shows the outcome: a set of tasks created in a Planner plan assigned to designated responsible individuals and with an appropriate label. In short, the script works (famous last words). At least, it does for me.

You can download the full script from GitHub. To run the script interactively, the account that signs in with Connect-MgGraph must be a member of the group that owns the plan. This is because the Graph SDK cmdlets use delegated permissions for interactive sessions. On the other hand, if the script runs interactively using an app and certificate thumbprint for authentication or runs using a managed identity as a scheduled Azure Automation runbook, the cmdlets can use application permissions and can access any plan.
There was more work than I expected to create and debug the script. Part of that is due to the somewhat obscure way Planner goes about its business. Part is due to a lack of documentation. In any case, the pain of chasing down dead ends and flawed ideas soon passes. The normal caveat applies that this code is designed to illustrate a principal rather than being a fully-fledged solution. Even so, enjoy working with Planner through PowerShell.



