Get-ScheduledTask | Select-Object * | Out-Gridview
Source: Guy Leech
Get-ScheduledTask | Select-Object * | Out-Gridview
Source: Guy Leech
Get-WmiObject Win32_PNPEntity | Sort-Object -Property PNPClass | Format-Table Name, PNPClass, DeviceID, Manufacturer, Status
Source: Thorsten E.
I often see scripts that are checking for True/False values using an If/Else statement like the one below.
if($value){
'True'
} else {
'False'
}
While this technically will work for Boolean values, there are situations where this will not work. For example, if you pass the string value of “False” to the statement above it will evaluate as True. This is because the if condition in that code is not checking for True, it is checking for if exists. In that statement anything that is not Boolean False, Null, an empty string, or 0 will return True. However, if you specify a value must be true or false, PowerShell will auto-convert things like the string equal to ‘False’ as actually being false.
This is why I always recommend using the full condition of if($value -eq $true). Not only will this give you the ability to account for variables you may not be able to control, it also gives you a way to handle non-Boolean values. You can test it out for yourself using the snippet below, and see how the different ways of writing this If/Else statement work out.
Function Test-Boolean($value, $test){
if($value -eq $true){
$Result='True'
} elseif ($value -eq $false) {
$Result='False'
} else {
$Result='Else'
}
if($value){
$IfElse = 'True'
} else {
$IfElse = 'False'
}
[pscustomobject]@{TrueFalse=$Result;IfElse=$IfElse;Value=$value;Test=$test}
}
Test-Boolean $true 'True boolean'
Test-Boolean 'true' 'True string'
Test-Boolean 1 '1 integer'
Test-Boolean $false 'False boolean'
Test-Boolean 'false' 'False string'
Test-Boolean 0 '0 integer'
Test-Boolean 'random' 'Any other string'
Test-Boolean 2 'Any other integer'
Test-Boolean ([string]::Empty) 'Empty string'
Test-Boolean ' ' 'Blank string'
Test-Boolean $null 'Null value'
After you run the snippet you should see results like the one below showing you how the two different If/Else statements evaluated the different values.
Recently one of my colleagues came to me with an interesting situation. His wife runs a homeschool co-op. Basically, a group of parents who homeschool their children, with different parents covering different subjects. Due to COVID-19, he needed a quick way to get them setup in Office 365 and Teams. So, I put together a quick upload script to import via a CVS. After talking with others in a similar situation and find out about the COVID-19 hackathon last weekend, we decided to make a user friendly interface and fully packaged upload script. If you know someone else in a similar situation, please feel free to point them to this – https://devpost.com/software/fast-deploy-microsoft-teams-for-education
Being married to someone who majored in English has made me extra conscious of my spelling and capitalization. So, for my blog posts, I’ve written a script to help me ensure my titles are properly capitalized. It is not perfect (i.e. it doesn’t do a dictionary lookup), but it follows the basic APA guidelines. I thought I would share it, in case others would find it useful.
# Split the string into individual words
$words = $string.Split()
[System.Collections.Generic.List[PSObject]]$stringArray = @()
For($i = 0; $i -lt $words.Count; $i++){
# Capitalize words of four or more letters, the first word, and the last word
if($words[$i].Length -gt 3 -or $i -eq 0 -or $i -eq ($words.Count - 1)){
# account for hyphen and capitalize words before and after
$words[$i] = @($words[$i].Split('-') | ForEach-Object{
$_.Substring(0,1).ToUpper() + $_.Substring(1,$_.Length-1)
}) -join('-')
}
# and the capitalized string to the array
$stringArray.Add($words[$i])
}
# join the words back together to form your title
$stringArray -join(' ')
PS C:\> $string = 'properly capitalize a title using PowerShell' >> $words = $string.Split() >> [System.Collections.Generic.List[PSObject]]$stringArray = @() >> For($i = 0; $i -lt $words.Count; $i++){ >> # Capitalize words of four or more letters, the first word, and the last word >> if($words[$i].Length -gt 3 -or $i -eq 0 -or $i -eq ($words.Count - 1)){ >> # account for hyphen and capitalize words before and after >> $words[$i] = @($words[$i].Split('-') | ForEach-Object{ >> $_.Substring(0,1).ToUpper() + $_.Substring(1,$_.Length-1) >> }) -join('-') >> } >> # and the capitalized string to the array >> $stringArray.Add($words[$i]) >> } >> $stringArray -join(' ') Properly Capitalize a Title Using PowerShell
Here is a quick little trick for removing the first entry in a fixed size array. This can be used when you receive the error message: Exception calling “RemoveAt” with “1” argument(s): “Collection was of a fixed size.”
# Remove first entry
$array = $array[1..($array.Length-1)]
PS C:\> $array = 1..5 >> Write-Host 'Initial Value' >> $array >> $array = $array[1..($array.Length-1)] >> Write-Host 'After Value' >> $array Initial Value 1 2 3 4 5 After Value 2 3 4 5
This script uses the GraphAPI to check all devices in Intune to see if they have a particular application installed.
$Application = "*PuTTY*"
$Username = '[email protected]'
Function Get-AuthToken {
<#
.SYNOPSIS
This function is used to authenticate with the Graph API REST interface
.DESCRIPTION
The function authenticate with the Graph API Interface with the tenant name
.EXAMPLE
Get-AuthToken
Authenticates you with the Graph API interface
.NOTES
NAME: Get-AuthToken
#>
[cmdletbinding()]
param
(
[Parameter(Mandatory=$true)]
[string]$User
)
$userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User
$tenant = $userUpn.Host
$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if(-not $AadModule) {
$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
}
if (-not $AadModule) {
write-host
throw("AzureAD Powershell module not installed..`n" +
"Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt")
}
# Getting path to ActiveDirectory Assemblies
# If the module count is greater than 1 find the latest version
if($AadModule.count -gt 1){
$Latest_Version = ($AadModule | select version | Sort-Object)[-1]
$aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
# Checking if there are multiple versions of the same module found
if($AadModule.count -gt 1){
$aadModule = $AadModule | select -Unique
}
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
} else {
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$Tenant"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result
# If the accesstoken is valid then create the authentication header
if($authResult.AccessToken){
# Creating header for Authorization token
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $authResult.AccessToken
'ExpiresOn'=$authResult.ExpiresOn
}
return $authHeader
} else {
throw "Authorization Access Token is null, please re-run authentication..."
}
}
Function Get-MsGraphData($Path) {
$FullUri = "https://graph.microsoft.com/beta/$Path"
[System.Collections.Generic.List[PSObject]]$Collection = @()
$NextLink = $FullUri
do {
$Result = Invoke-RestMethod -Method Get -Uri $NextLink -Headers $AuthHeader
if($Result.'@odata.count'){
$Result.value | ForEach-Object{$Collection.Add($_)}
} else {
$Collection.Add($Result)
}
$NextLink = $Result.'@odata.nextLink'
} while ($NextLink)
return $Collection
}
# Get authentication token
$AuthHeader = Get-AuthToken -User $Username
# Get all devices in Intune
$AllDevices = Get-MsGraphData "deviceManagement/managedDevices"
# Get detected app for each device and check for app name
[System.Collections.Generic.List[PSObject]]$FoundApp = @()
$wp = 1
foreach($Device in $AllDevices) {
Write-Progress -Activity "Found $($FoundApp.count)" -Status "$wp of $($AllDevices.count)" -PercentComplete $(($wp/$($AllDevices.count))*100) -id 1
$AppData = Get-MsGraphData "deviceManagement/managedDevices/$($Device.id)?`$expand=detectedApps"
$DetectedApp = $AppData.detectedApps | ?{$_.displayname -like $Application}
if($DetectedApp){
$DetectedApp | Select-Object @{l='DeviceName';e={$Device.DeviceName}}, @{l='Application';e={$_.displayname}}, Version, SizeInByte,
@{l='LastSyncDateTime';e={$Device.lastSyncDateTime}}, @{l='DeviceId';e={$Device.id}} | Foreach-Object { $FoundApp.Add($_) }
}
$wp++
}
Write-Progress -Activity "Done" -Id 1 -Completed
$FoundApp | Sort-Object deviceName | Format-Table
PowerShell remoting help in a lot of areas, but there are times when you need to use PSExec. For those instances, I’ve created a function that you can use to run a command on a remote machine using PSExec.
Function ExecutePsExec($computer, $command){
$ping = Test-Connection $computer -Count 1 -Quiet
if($ping){
$StdOutput = (Join-path $env:temp "$($computer).txt")
Start-Process -FilePath $psexec -ArgumentList "-s \\$computer $command" -Wait -RedirectStandardOutput $StdOutput -WindowStyle Hidden
$Results = Get-Content $StdOutput -raw
Remove-Item $StdOutput -Force
} else {
$Results = "Not online"
}
[pscustomobject]@{
Computer = $computer
Results = $Results
}
}
# path to PsExec on your local machine
$script:psexec = "C:\Tools\PsExec.exe"
# the command to run
$command = 'cmd /c "powershell.exe -ExecutionPolicy ByPass \\SHARE01\Scripts\Demo.ps1"'
# execute the command on the remote computer
ExecutePsExec -computer 'MYPC01' -command $command
[System.Collections.Generic.List[PSObject]] $page = @()
$j = 0
$blank52 = "<td height=""52""> </td>`n" * 9
$blank20 = "<td height=""20""><br></td>`n" * 9
while($j -lt 5){
[System.Collections.Generic.List[PSObject]] $rowA = @()
[System.Collections.Generic.List[PSObject]] $rowB = @()
$i=0
while($i -lt 5){
$a = Get-Random -Minimum 1 -Maximum 10
$b = Get-Random -Minimum 0 -Maximum (9-$a+1)
$c = Get-Random -Minimum 1 -Maximum 10
$d = Get-Random -Minimum 0 -Maximum (9-$c+1)
if(($b + $d) -gt 0){
if($b -eq 0){$b=' '}
$rowA.Add("<td class=""xl66"" height=""52"" width=""115"">$a$c</td>`n")
$rowB.Add("<td class=""xl65"" height=""52"" width=""115"">+ $b$d</td>`n")
$i++
}
}
$tableRows = New-Object System.Text.StringBuilder
$tableRows.Append('<tr height="52">') | Out-Null
$tableRows.Append($rowA -join('<td class="xl66" width="15"><br>')) | Out-Null
$tableRows.Append('</tr><tr height="52">') | Out-Null
$tableRows.Append($rowB -join('<td class="xl66" width="15"><br>')) | Out-Null
$tableRows.Append("</tr><tr height=""52"">$blank52</tr>") | Out-Null
$page.Add($tableRows.ToString())
$j++
}
$bodyTop = @'
<html><head><title>math</title><style>.xl65{mso-style-parent:style0;font-size:36.0pt;mso-number-format:"\@";
text-align:right;border-top:none;border-right:none;border-bottom:1.5pt solid windowtext;border-left:none;}
.xl66{mso-style-parent:style0;font-size:36.0pt;mso-number-format:"\@";text-align:right;}</style></head><body>
<table style="text-align: left; width: 635px; height: 60px;" border="0" cellpadding="0" cellspacing="0"><tbody>
'@
$bodyBotton = @'
</tbody></table><br><br></body></html>
'@
$bodyTop + $page -join("<tr height=""20"">$blank20</tr>") + $bodyBotton | out-file '.\math.html'
$ResourceGroupName = ''
$AutomationAccountName = ''
# Get all variables
$variables = Get-AzureRMAutomationVariable -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName
# parse through each unencrypted variable
Foreach($var in $variables | Where-Object{$_.Encrypted -ne $True}){
# remove the unencrypted variable
Remove-AzureRMAutomationVariable -ResourceGroupName $var.ResourceGroupName -AutomationAccountName $var.AutomationAccountName -Name $var.Name
# recreate the variable, with the same values and encrypt it
New-AzureRMAutomationVariable -ResourceGroupName $var.ResourceGroupName -AutomationAccountName $var.AutomationAccountName -Name $var.Name -Encrypted $True -Value $var.Value -Description $var.Description
}