Microsoft cloud engineer - SharePoint, Office 365, Azure, DotNet, Angular, JavaScript.
Microsoft cloud engineer - SharePoint, Office 365, Azure, DotNet, Angular, JavaScript.

PowerShell

Practical PowerShell Logs

All scheduled PowerShell files should generate LOGs.  “Start-Transcript” is a great cmdlet for this.  Adding a few more features can boost operations support.   LOGs answer essentials support questions like:

  • Which parent PS1 generated this LOG?
  • Did script perform needed functions?
  • Any errors?
  • How long did it take?
  • Which user and computer ran the script?

Below is code template I recommend to for scheduled PowerShell jobs to generate a LOG. Key features include:

  • Auto detect current folder and script PS1
  • Create  \LOG\ subfolder
  • Prefix to match parent PS1
  • Suffix with unique date time stamp
  • Elapsed run duration (Days, Hours, Minutes)

Thank you to @ToddKlindt for improvements to formula and elapsed time.  Cheers. 

shades_smile

Video

Code

function Main() {
    ### YOUR CODE HERE
}

# Open Log
$prefix = $MyInvocation.MyCommand.Name
$host.UI.RawUI.WindowTitle = $prefix
$stamp = Get-Date -UFormat "%Y-%m-%d-%H-%M-%S"
Start-Transcript "$PSScriptRoot\log\$prefix-$stamp.log"
$start = Get-Date

Main

# Close Log
$end = Get-Date
$totaltime = $end - $start
Write-Host "`nTime Elapsed: $($totaltime.tostring("hh\:mm\:ss"))"
Stop-Transcript

Download

https://github.com/spjeff/spadmin/blob/master/Practical-PowerShell-LOGs.ps1

VIDEO – Load PNP the Right Way

Quick post about detecting if PowerShell PNP is available on the local PC and installing is missing (for new systems) to make PS1 script more portable across servers.(1) Detect command (2) Install module if missing (3) Import module. Cheers

shades_smile

Video

Code

# Load PNP module, the right way
Add-Type -Assembly "System.IO.Compression.FileSystem" -ErrorAction SilentlyContinue | Out-Null
$pnp = Get-Command Connect-PnPOnline -ErrorAction SilentlyContinue
if (!$pnp) {
    Install-Module "SharePointPnPPowerShellOnline" -Force
}
Import-Module "SharePointPnPPowerShellOnline" -ErrorAction SilentlyContinue | Out-Null

References

VIDEO – How to Add Contact for other users with MS Graph API

Wanted to share a quick demo for how to query and create Exchange Contacts for another user in Office 365 tenant with MS Graph API.   Biggest challenge was permission grant in two places (1) MS Graph API in Azure Applications and (2) Exchange Folder grant Owner to user executing the MS Graph API.  Updated blog post with second video to execute Graph API from PowerShell for automation and scheduling.   Cheers

shades_smile

Video 1 – Graph Explorer Web GUI

Video 2 – Graph API from PowerShell

PowerShell – Grant Exchange Folder

$Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session
Add-MailboxFolderPermission -Identity "george@spjeff.com:\Contacts" –User "spjeff@spjeff.com" –AccessRights "Owner"

PowerShell – Execute Graph API

# from https://blog.mastykarz.nl/building-applications-office-365-apis-any-platform/

# Config
$clientID = "34f34d49-86b7-4437-a332-6fecaf95a244"
$tenantName = "spjeff.onmicrosoft.com"
$ClientSecret = "secret-goes-here"
$Username = "spjeff@spjeff.com"
$Password = "password-goes-here"

# Access Token
$ReqTokenBody = @{
    Grant_Type    = "Password"
    client_Id     = $clientID
    Client_Secret = $clientSecret
    Username      = $Username
    Password      = $Password
    Scope         = "https://graph.microsoft.com/.default"
} 
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
$TokenResponse


# Data call - READ
$apis = @(
'https://graph.microsoft.com/v1.0/me/contacts',
'https://graph.microsoft.com/v1.0/me',
'https://graph.microsoft.com/v1.0/users',
'https://graph.microsoft.com/v1.0/users/george@spjeff.com/contacts')
$apis |% {
    Write-Host $_ -Fore Yellow
    Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $_ -Method GET -Body $body -ContentType "text/plain"
}

# Data call - WRITE
$newcontact = '{"givenName": "Test","surname": "Contact","emailAddresses": [{"address": "test@contact.com","name": "Pavel Bansky"}],"businessPhones": ["+1 732 555 0102"]}'
$api = 'https://graph.microsoft.com/v1.0/users/george@spjeff.com/contacts'
Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $api -Method "POST" -Body $newcontact -ContentType "application/json"

Screenshots

2020-01-28_06-59-19
2020-01-28_07-01-09
image
image
image

References

    © Copyright 2016
    @ SPJeff

    Return to Top ▲Return to Top ▲