powershell hotfix script not working - powershell

I've been trying to find a way to remotely, from a jumphost, verify that a patch has been installed. I am using a script I found on a Microsoft page but it shoots back an error. I've been trying to find a solution for days with no luck could any one please help me.---update
This is the error I get:
You cannot call a method on a null-valued expression.
At C:\Temp\HOTFIX.ps1:53 char:18
+ $Sheet.Cells.Item <<<< ($intRow,2) ="status"
+ CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Temp\HOTFIX.ps1:54 char:18
+ $Sheet.Cells.Item <<<< ($intRow,3) ="Patch status"
+ CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Temp\HOTFIX.ps1:55 char:18
+ $Sheet.Cells.Item <<<< ($intRow,4) ="OS"
+ CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Script:
#Check for a specific patch on remote PCs v1.2
# Tom Latham 04/02/2010
#
# Added v1.1: Error messaages
# Added v1.2: GUI Inputs
# Function to open file dialog box and select a file
Function Get-FileName($initialDirectory)
{
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "Text Files (*.txt)| *.txt" # Set the file types visible to dialog
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
}
# Function to prompt user for kb number
Function Get-Input
{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Enter KB Number"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$objForm.Close()}})
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Please enter the KB number below (kbxxxxxx):"
$objForm.Controls.Add($objLabel)
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,40)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
$x
}
# Main Program --------------------------------------
# Do not display errors
$erroractionpreference = "SilentlyContinue"
# Clear screen
clear-host
# Store user credentials
$cred = get-credential
# Supply text file of all PCs to be checked and KB number to search for
# Run Open File Dialog
$filename = Get-FileName -initialDirectory "c:"
# Get path of file to be used in storing results
$path = split-path $filename
# If kbresults.txt exists, delete it
if (test-path $path\kbresults.txt)
{ remove-item $path\kbresults.txt }
# Get kb number
$kb = Get-Input
# Extract content from filename object
$computernames = get-content $filename
# For each computer in list
foreach ($computer in $computernames)
{
# Set query string to query ping status
$strQuery = "select * from win32_pingstatus where address = '" + $computer + "'"
# Get WMI object using query
$wmi = gwmi -query $strquery
# If machine pings (status = 0)
if ($wmi.statuscode -eq 0)
{
# Get WMI object on computer where hotfixid equals our kb number
# Use stored user credentials
$checkkb = gwmi win32_QuickFixEngineering -computer $computer -credential $cred | where {$_.hotfixid -eq $kb} | select-object hotfixid, description
switch -regex ($Error[ 0 ].Exception)
{
"The RPC server is unavailable"
{
write-host -f blue $computer "`t" "RPC Unavailable on $computer" "`r"
"$computer `t RPC Unavailable." | out-file $path\kbresults.txt -append
continue
}
"Access denied"
{
write-host -f blue $computer "`t" "Access Denied" "`r"
"$computer `t Access Denied." | out-file $path\kbresults.txt -append
continue
}
"Access is denied"
{
write-host -f blue $computer "`t" "Access Denied" "`r"
"$computer `t Access Denied." | out-file $path\kbresults.txt -append
continue
}
# No error -> record our info!
$null
{
# If kb numbers match
if ($checkkb.hotfixid -eq $kb)
{
# Patch is installed. Test reboot status.
# Connect to remote registry hive (HKLM)
$regHive = [Microsoft.Win32.RegistryHive]"LocalMachine";
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($regHive,$computer);
# Set subkey to 'UpdateExeVolatile', the existence of which show reboot pending status
$subKey = $regKey.OpenSubKey("SOFTWARE\Microsoft\Updates\UpdateExeVolatile");
# If subkey is not found
if (!$subKey)
{
# Patch is installed
write-host -f green $computer "`t" $checkkb.description "`r"
"$computer `t Installed." | out-file $path\kbresults.txt -append
}
else
{
# Patch installed. Reboot required.
write-host -f green $computer "`t" $checkkb.description "`r"
"$computer `t Reboot Required" | out-file $path\kbresults.txt -append
}
}
else
{
# Patch is not installed.
write-host -f red $computer "`t" "Not Found" "`r"
"$computer `t Not Installed." | out-file $path\kbresults.txt -append
}
}
}
$Error.clear()
}
else
{
# Machine doesn't ping. Write to screen and append to results file.
write-host $computer "`t" "Cannot ping." "`r"
"$computer `t Ping failed." | out-file $path\kbresults.txt -append
}
}

Related

How to Make my Powershell script discover a Desktop on my network and delete user profiles remotely

I am fairly new with powershell scripting and trying to learn. I am trying to create a PS1 file that runs with a GUI for easy use for other people on my team, that can delete profiles off of a Desktop/Laptop remotely. I have a script below that works for local profiles and would like to enhance it for remote PC's so we dont physically have to collect devices when cleaning up desktops/laptops that are filled with profiles. These computers have a program that runs that refreshes the profiles daily so a script that cleans based on days since last log in will not work.
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(400,300)
$form.Text = "Delete User Profiles"
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Size = New-Object System.Drawing.Size(360,200)
$listBox.Location = New-Object System.Drawing.Point(20,20)
$listBox.SelectionMode = [System.Windows.Forms.SelectionMode]::MultiSimple
$userProfiles = Get-ciminstance -classname Win32_UserProfile
foreach ($userProfile in $userProfiles) {
if (($userProfile.localpath -notmatch "Public") -and ($userProfile.localpath -notmatch "Default")) {
$listBox.Items.Add($userProfile.localpath)
}
}
$form.Controls.Add($listBox)
$deleteButton = New-Object System.Windows.Forms.Button
$deleteButton.Size = New-Object System.Drawing.Size(100,30)
$deleteButton.Location = New-Object System.Drawing.Point(20,230)
$deleteButton.Text = "Delete"
$deleteButton.Add_Click({
foreach ($item in $listBox.SelectedItems) {
##Remove-Item -Path "$item" -Recurse -Force
##Properly removing item from WMI. note: -whatif currently specified so the operation doesn't actually occur
get-ciminstance -classname win32_userprofile | where-object -property localpath -like $item | remove-ciminstance ##-whatif
}
[System.Windows.Forms.MessageBox]::Show("Done","Delete Dialog",[Windows.Forms.MessageBoxButtons]::OkCancel)
})
$form.Controls.Add($deleteButton)
#$form.Controls.Add($listBox)
$showButton = New-Object System.Windows.Forms.Button
$showButton.Size = New-Object System.Drawing.Size(100,30)
$showButton.Location = New-Object System.Drawing.Point(140,230)
$showButton.Text = "Refresh"# "Show"
$showButton.Add_Click({
# foreach ($item in $listBox.SelectedItems) {
# [System.Windows.Forms.MessageBox]::Show("You have chosen to remove $item","Profile Selection Dialog",[Windows.Forms.MessageBoxButtons]::OkCancel)
# }
$listBox.Items.Clear()
$userProfiles = Get-ciminstance -classname Win32_UserProfile
foreach ($userProfile in $userProfiles) {
if (($userProfile.localpath -notmatch "Public") -and ($userProfile.localpath -notmatch "Default")) {
$listBox.Items.Add($userProfile.localpath)
}
}
})
$form.Controls.Add($showButton)
$form.ShowDialog()
Please Help.........

Getting Error while running Powershell Script to add Site Content Link

$adminUPN="xxxxx#Home500.onmicrosoft.com"
$orgName="xxxxxx"
$userCredential = Get-Credential -UserName $adminUPN -Message "Type the password."
Connect-SPOService -Url https://$orgName-admin.sharepoint.com -Credential $userCredential
# Begin the process
$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")
#Add SharePoint PowerShell SnapIn if not already added
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell" -EA SilentlyContinue
}
CLS
$StartTime = $(get-date -f F)
$timeStamp = Get-Date -format "MM_dd_yy_hh_mm"
#Get Current folder file path
$invocation = (Get-Variable MyInvocation).Value
$currentPath = Split-Path $invocation.MyCommand.Path
$currentPath = $currentPath + "\"
#Config File Path
#$configPath = $currentPath + "Config.xml"
$configPath = "C:\Users\EMXBG\Downloads\Script_AddSiteContent\Script_AddSiteContent\Config.xml"
#fetching details from config.xml
[xml]$configXML = Get-Content $configPath
$inputFileName = [string]$configXML.Config.Constants.InputFileName
$errorFileName = [string]$configXML.Config.Constants.ErrorFileName
$outFilePath = [string]$configXML.Config.Constants.OutputFileName
#Source File path containing list of WebApplications in a farm.
$webApplFilePath = $currentPath + $inputFileName
#Output File path of the exported AD Security Groups with Site collection and Group Name details.
$sitesFilePath = $currentPath + $outFilePath
#File path of the file which will capture all the errors while running the script.
$errorPath = $currentPath + $errorFileName + $timeStamp + ".csv"
# Creating object to write logging into the error and output file
$sitesFile = New-Object System.IO.StreamWriter $sitesFilePath
$errorfile = New-Object System.IO.StreamWriter $errorPath
# Fetching SharePoint WebApplications list from a CSV file
$CSVData = Import-CSV -path $webApplFilePath
$sitesFile.WriteLine("SiteCollectionName"+","+"SiteURL")
$errorfile.WriteLine("SiteURL"+"`t"+"ExceptionLevel"+"`t"+"ExceptionMsg");
addSiteContentLink $CSVData
$sitesFile.Close()
$errorfile.Close()
# Function to add Site Content link in thes where it does not exists
function addSiteContentLink($CSVData)
{
try
{
$compareText = "Site contents"
foreach ($row in $CSVData)
{
$webUrl = $row.webUrl
#$username = $row.username
#$password = $row.password
#Get Web Application and credentials
#$securePass = ConvertTo-SecureString $password -AsPlainText -Force
#$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($webUrl)
#$ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePass)
# Get the collection of navigation nodes from the quick launch bar
#$web = $ctx.Web
$quickLaunch = $webUrl.Navigation.QuickLaunch
try
{
#Iterate through each iten in Quick launch menu
foreach($quickLaunch in $web)
{
if ($quickLaunch -contains $compareText)
{
Write-Host "Site Content link Exists!"
}
else
{
# Add a new navigation node
$navNode = New-Object Microsoft.SharePoint.Client.NavigationNodeCreationInformation
$navNode.AsLastNode = $true
$navNode.Title = "Site Contents"
$navNode.Url = $web.Url + "_layouts/15/viewlsts.aspx"
$navNode.IsExternal = $false
$ctx.Load($quickLaunchColl.Add($navNode))
$ctx.ExecuteQuery()
}
}
}
catch
{
Write-Host("Exception at Site Collection Url :" + $currentSite.Url)
$errorfile.WriteLine($currentSite.Url+"`t"+"`t"+$_.Exception.Message)
}
}
#Export Data to CSV
$sitesCollection | export-csv $sitesFile -notypeinformation
$site.Dispose()
}
catch
{
Write-Host("Exception at Site Collection Url :" +$currentSite.Url)
$errorfile.WriteLine($currentSite.Url+"`t"+"SiteCollection"+"`t"+$_.Exception.Message)
}
}
Below is the Error I am getting
Export-Csv : Cannot bind argument to parameter 'InputObject' because it is null.
At C:\Users\EMXBG\Downloads\Script_AddSiteContent\Script_AddSiteContent\ScriptForSiteContentLinkQuickLaunch - Copy.ps1:126 char:29
+ $sitesCollection | export-csv $sitesFile -notypeinformation
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Export-Csv], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportCsvCommand
This error is probably because $sitesCollection is empty/null. I can't see anything in your code that assigns it a value.

replace text with a textbox input using variable

In my script I have a textbox- the user inserts text in it and than I want to change the text in a file (which the script creates earlier) to what the user inserted in the textbox.
The problem: it does deletes the part I wanted to be changed in the file- but it doesn`t write the text of the user instead. I also tried to locate the variable in the if loop- and it did changed the text like i wanted, but when I run the script again it wrote the old text in the disabled textbox.
my script is kinda long so I wont post all of it, but here are the importent parts. Thanks for the help!
#This creates a checkbox called dsp.z
$objDspCheckbox = New-Object System.Windows.Forms.Checkbox
$objDspCheckbox.Location = New-Object System.Drawing.Size(20,40)
$objDspCheckbox.Size = New-Object System.Drawing.Size(150,20)
$objDspCheckbox.Text = "dsp.z"
$objDspCheckbox.TabIndex = 0
$objForm.Controls.Add($objDspCheckbox)
#This creates the TextBox1 and put it on disable
$objTextBox1 = New-Object System.Windows.Forms.TextBox
$objTextBox1.Location = New-Object System.Drawing.Size(450,40)
$objTextBox1.Size = New-Object System.Drawing.Size(140,150)
$objTextBox1.TabIndex = 3
$objTextBox1.text = $text1
$objTextBox1.Enabled = $false
$objForm.Controls.Add($objTextBox1)
#This creates a checkbox for textbox1
$objDsp2Checkbox = New-Object System.Windows.Forms.Checkbox
$objDsp2Checkbox.Location = New-Object System.Drawing.Size(430,40)
$objDsp2Checkbox.Size = New-Object System.Drawing.Size(150,20)
$objDsp2Checkbox.TabIndex = 0
$objForm.Controls.Add($objDsp2Checkbox)
#Enables the textbox when user check the box:
#textbox1
$objDsp2Checkbox_OnClick = {
if ($objDsp2Checkbox.Checked -eq $true)
{
$objTextBox1.Enabled = $true
}
elseif ($objDsp2Checkbox.Checked -eq $false)
{
$objTextBox1.Enabled = $false
}
}
$objDsp2Checkbox.Add_Click($objDsp2Checkbox_OnClick)
#variables
$text1=$objTextBox1.Text
#This creates the ok and cancle buttons:
#ok Button
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(220,155)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click(
{
if (($objDspCheckbox.Checked -eq $true) -and ($objDsp2Checkbox.Checked -eq $true))
{
New-Item $path -itemtype file -name Dsp.json -value "old" ;((Get-Content "c:\users\$env:USERNAME\documents\Json\dsp.json") -replace 'old', $text1 | out-file "c:\users\$env:USERNAME\documents\Json\dsp.json") ;$objForm.close()
}
Try to Change This Line (specifly the $text1) to $objTextBox1.Text :
New-Item $path -itemtype file -name Dsp.json -value "old" ;
((Get-Content "c:\users\$env:USERNAME\documents\Json\dsp.json") -replace 'old', $text1 |
Out-file "c:\users\$env:USERNAME\documents\Json\dsp.json") ;$objForm.close()
To:
New-Item $path -itemtype file -name Dsp.json -value "old" ;
((Get-Content "c:\users\$env:USERNAME\documents\Json\dsp.json") -replace 'old', $objTextBox1.Text |
Out-file "c:\users\$env:USERNAME\documents\Json\dsp.json") ;$objForm.close()
I'm not sure if it's the case but if you just need to save the textbox text to file there's an easier approach :
$objTextBox1.Text | Out-file "c:\users\$env:USERNAME\documents\Json\dsp.json")

SPO Powershell Set Permissions Error in RoleDefinitionBindingCollection Call

On Sharepoint Online, using Powershell, I am trying to set list item permissions, and am finding dozens of tutorials that use a RoleDefinitionBindingCollection($ctx) call...
When I do this, though, I get the following error:
New-Object : Cannot find an overload for "RoleDefinitionBindingCollection" and
the argument count: "1".At
C:\Users\thebear\Desktop\SEDA\SEDASetIPPermissions.ps1:172 char:31
+ ... entReader = New-Object Microsoft.SharePoint.Client.RoleDefinitionBind ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
I am iterating through Doclib folders, then through the Folder.Files, checking for a value in a custom field, and setting the permissions on the matching items. EDIT: Here is the full code:
# cd 'C:\Users\thebear\Desktop\SEDA'
# .\SEDASetIPPermissions test KLY KLY1
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Add-Type -Path "c:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "c:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
If($($args.Count) -ne 3)
{
Write-Host “Usage: .\SEDASetIPPermissions <'prod' or 'test'> <ProgCode i.e. 'LCL' or 'All'> <IPGroup i.e. 'KLY1' or 'All'>"
break
}
$Site = if($args[0] -eq 'prod') {'sedasearch'} elseif ($args[0] -eq 'test') {'sedasearchtest'}
$Lib = $args[1]
$IPGroup = $args[2]
# Get Connected
$Cred = Get-Credential
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $Cred.UserName, $Cred.Password
$Url = "https://MySite.sharepoint.com/sites/$Site"
Connect-SPOnline -Url $Url -Credentials $Credentials
# Get Client Context
$ctx = Get-SPOContext
$ctx.RequestTimeout = 1000000
$ctx.ExecuteQuery()
# Get Web & Lists
$web = $ctx.Web
$ctx.Load($web)
$ctx.Load($web.Lists)
$ctx.Load($web.RoleDefinitions)
$ctx.ExecuteQuery()
$lists = $web.Lists
# Get Site Groups
$groups = $web.SiteGroups
$ctx.Load($groups)
$ctx.ExecuteQuery()
# Get Target Group
$groupFound = $false
$ScriptStart = Get-Date
foreach ($group in $groups)
{
if ($group.Title -eq "SEDA Admins")
{
$AdminGroupID = $group.Id
}
elseif($group.Title -eq $IPGroup + " Security Group")
{
$groupFound = $true
$IPGroupID = $group.Id
Write-Host "`n'$IPGroup Security Group' Found...`n" -ForegroundColor Green
}
}
if (!$groupFound) { Write-Host "`n'$IPGroup Security Group' NOT Found...`n" -ForegroundColor Red; break }
# Get Target List
$list = $lists.GetByTitle($Lib + " Library")
$ctx.Load($list)
$ctx.Load($list.RootFolder)
$ctx.Load($list.Fields)
$ctx.ExecuteQuery()
if($list -ne $null)
{ "`n'{0}' Found...`n" -f $list.Title | Write-Host -ForegroundColor Green }
else
{ "`n'{0}' NOT Found...`n" -f $list.Title | Write-Host -ForegroundColor Red; break }
# Get List Folders
$folders = $list.RootFolder.Folders
$ctx.Load($folders)
$ctx.ExecuteQuery()
$folders = $folders | sort Name
# Set Up Group and Admin Permissions (if not already there)
$RoleDefinitions = $web.RoleDefinitions
$ctx.Load($RoleDefinitions)
$ctx.ExecuteQuery()
$foundIPGroupRole = $false
$foundIPAdminRole = $false
foreach ($role in $RoleDefinitions)
{
if ($role.Name -eq "Read")
{
$IPGroupRole = $role
$foundIPGroupRole = $true
}
elseif ($role.Name -eq "Full Control")
{
$IPAdminRole = $role
$foundIPAdminRole = $true
}
}
# Set the permissions for 'IP Group'
$roleAssignmentReader = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignmentReader.Add($IPGroupRole)
# Set the permissions for 'IP Admin'
$roleAssignmentAdmin = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
$roleAssignmentAdmin.Add($IPAdminRole)
# Set Counters
$FileCount = 0
$FailCount = 0
foreach ($folder in $folders)
{
$FolderFileCount = 0
$ctx.Load($folder)
$ctx.Load($folder.ListItemAllFields)
$ctx.ExecuteQuery()
if ($folder.ItemCount -lt 5000)
{
$files = $folder.Files
$ctx.Load($files)
$ctx.ExecuteQuery()
"`nProcessing Folder {0}..." -f $folder.Name | Write-Host -ForegroundColor Green
}
else
{ "`nFolder {0} Exceeds 5000 Items...`n" -f $folder.Url | Write-Host -ForegroundColor Red; continue }
foreach ($file in $files)
{
$ctx.Load($file)
$ctx.Load($file.ListItemAllFields)
$ctx.ExecuteQuery()
$item = $file.ListItemAllFields
$ctx.Load($item)
$ctx.ExecuteQuery()
$name = $file.Name
$group = $item.get_item('IPGroup')
if($group -eq $IPGroup)
{
"`nProcessing File {0}...`n" -f $name | Write-Host -ForegroundColor Green;
# Break inheritance on the list item and remove existing permissons.
# NOTE: Use $item.ResetRoleInheritance() to Restore Roll Inheritance
$item.BreakRoleInheritance($false, $true)
# Apply the two permission roles to the list item.
$ctx.Load($item.RoleAssignments.Add($IPGroupID, $roleAssignmentReader))
$ctx.Load($item.RoleAssignments.Add($AdminGroupID, $roleAssignmentAdmin))
# Update the list item and execute
$item.Update()
$ctx.ExecuteQuery()
"`nProcessed File {0}...`n" -f $name | Write-Host -ForegroundColor Green;
}
$FolderFileCount += 1
if($FolderFileCount % 1000 -eq 0) { "{0}K" -f ($FolderFileCount/1000).ToString() | Write-Host }
elseif($FolderFileCount % 100 -eq 0) {Write-Host '*'}
else {Write-Host -NoNewline '.'}
}
}
“`n{0} Files Processed, {1} Error(s), Elapsed Time: {2}" -f $FileCount, $FailCount, $((Get-Date) - $ScriptStart) | Write-Host
$ctx appears to be legit... what else could be causing this error (for a day now)?
This error occurs since RoleDefinitionBindingCollection constructor expects ClientRuntimeContext object but the following line:
$ctx = Get-SPOContext
returns object of OfficeDevPnP.Core.PnPClientContext type. Even though it inherits from ClientRuntimeContext object (PnPClientContext -> ClientContext -> ClientRuntimeContext) it could not be used for instantiating of Microsoft.SharePoint.Client.RoleDefinitionBindingCollection object.
Solution
One option would be to replace the lines:
Connect-SPOnline -Url $Url -Credentials $Credentials
#Get Client Context
$ctx = Get-SPOContext
with
$ctx = Get-Context -WebUrl $Url -UserName $Credentials.UserName -Password $Credentials.Password
where
Function Get-Context([String]$WebUrl,[String]$UserName,[System.Security.SecureString]$Password) {
$context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $Password)
return $context
}
which returns Microsoft.SharePoint.Client.ClientContext object.
According to this link below. The Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx) is looking for a url as an argument, not a filename.
https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.roledefinitionbindingcollection.aspx

Powershell script works in ISE but not in Run With Powershell

I had develop a script that basically restart a service in a remove server based on a selection.
This selection is done by a form.
The problem is... when I run this using the ISE... the script work totally fine.
When I run this using the RIGHT CLICK / RUN with Powershell
My form doesn't work. The Button that I had created didn't appear...
What can be wrong?
Here is my code:
Function Write-Centered {
Param( [string] $message,
[string] $color = "black")
$offsetvalue = [Math]::Round(([Console]::WindowWidth / 2) + ($message.Length / 2))
Write-Host ("{0,$offsetvalue}" -f $message) -ForegroundColor $color
}
clear
$timestamp=Get-date -format yyyy_MM_dd_hh_mm_ss
$systems = #(
("System 1","Server1","bmc_ctsa_sm_SAP_Instance_2"),
("System 2","Server2","bmc_ctsa_sm_SAP_Instance_6"),
("System 3","Server3","bmc_ctsa_sm_SAP_Instance_6")
)
Write-Centered "Service Restart Tool" "Green"
Write-Centered "Choose the target system you would like to restart" "Green"
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$Form1 = New-Object System.Windows.Forms.Form
$Form1.ClientSize = New-Object System.Drawing.Size(300, 100)
$form1.topmost = $true
$Form1.Controls.Add($Button)
$Form1.Text = "SSPR Restart Tool"
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Point(150, 25)
$Button.Size = New-Object System.Drawing.Size(120, 25)
$Button.add_Click({
$label.Text = $comboBox1.SelectedItem.ToString()
$Form1.Close()
})
$Button.Text = "Start Process"
$Label = New-Object System.Windows.Forms.Label
$Label.Location = New-Object System.Drawing.Point(10, 10)
$Label.Size = New-Object System.Drawing.Size(300, 15)
$Label.Text = "Please select the system you would like to restart"
$Form1.Controls.Add($Label)
$comboBox1 = New-Object System.Windows.Forms.ComboBox
$comboBox1.Location = New-Object System.Drawing.Point(10, 25)
$comboBox1.Size = New-Object System.Drawing.Size(120, 25)
foreach($system in $systems)
{
$comboBox1.Items.add($system[0]) | Out-Null
}
$Form1.Controls.Add($comboBox1)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(70, 90)
$label.Size = New-Object System.Drawing.Size(98, 23)
$label.Text = ""
$Form1.Controls.Add($label)
[void]$form1.showdialog()
Write-Centered $comboBox1.Text "Yellow"
$do=0
$i=0
do {
if ($comboBox1.Text -eq $systems[$i][0]){
$result=$i
$i++
}
$do++
}while ($do -le $systems.length-1)
$System=$systems[$result][0]
$Server=$systems[$result][1]
$Instance=$systems[$result][2]
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
"Start the process."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
"Cancel the process."
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$result = $host.ui.PromptForChoice("",`
"`nWould you like to progress with the service restart? `n`nSystem: $System`nServer: $Server`nInstance: $Instance", $options, 0)
if ($result -eq 0) {
$services = Get-Service -computername $Server -name $Instance
$target=$services.name
$sharefolder = "\\"+$Server+"\c$"
New-PSDrive –Name “X” –PSProvider FileSystem –Root $sharefolder | out-null
Write-Host ======================================================
Write-Host = Searching for the destination folder. Please wait...
Write-Host ======================================================
$test1=Test-Path "X:\Program Files (x86)\BMC Software"
$test2=Test-Path "X:\Program Files\BMC Software"
if ($test1) {
$file=Get-ChildItem "X:\Program Files (x86)\BMC Software" -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "CONTROL-SA"}
} elseif ($test2){
$file=Get-ChildItem "X:\Program Files\BMC Software" -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "CONTROL-SA"}
}
$fullname=$file.FullName+"\Services Manager\"+$Instance
$fullname
Write-Host ======================================================
Write-Host = Stopping $target
Write-Host ======================================================
Get-Service -Name $target -ComputerName $Server | Set-Service -Status Stopped
$src=$fullname+"\log\*"
$des=$fullname+"\log_bkp_"+$timestamp+"\"
Write-Host ======================================================
Write-Host = Perform LOG folder backup for troubleshooting
Write-Host ======================================================
New-Item $des -type directory | out-null
Move-item -path $src -destination $des -force -verbose
#Remove-item $src -force -recurse -verbose
Get-Service -Name $target -ComputerName $Server | Set-Service -Status Running
Remove-PSDrive -Name "X" | out-null
}
elseif ($result -eq 1) {
BREAK
}
Write-Host ======================================================
Write-Host = Process Completed
Write-Host = You may now close this window
Write-Host ======================================================
Start-Sleep -s 120
Have the screen captures of the results.. but low reputation prevent me to post it... :-(
I typo'd my comment, it should be Controls and not Controles, but that's the issue. After $Form1.Controls.Add($label) add a new line:
$Form1.Controls.Add($Button)
See if it doesn't work as expected at that time. It does for me when I tested it.
A wrong place for the $Form1.Controls.Add($Button) was preventing my code to show up the control button...
Thanks for the hint