This PowerShell script works (not mine, I found it - data has been changed to dummy data here) - it Syncs Documents from a SharePoint Site to the users OneDrive:
#region Functions
function Sync-SharepointLocation {
param (
[guid]$siteId,
[guid]$webId,
[guid]$listId,
[mailaddress]$userEmail,
[string]$webUrl,
[string]$webTitle,
[string]$listTitle,
[string]$syncPath
)
try {
Add-Type -AssemblyName System.Web
#Encode site, web, list, url & email
[string]$siteId = [System.Web.HttpUtility]::UrlEncode($siteId)
[string]$webId = [System.Web.HttpUtility]::UrlEncode($webId)
[string]$listId = [System.Web.HttpUtility]::UrlEncode($listId)
[string]$userEmail = [System.Web.HttpUtility]::UrlEncode($userEmail)
[string]$webUrl = [System.Web.HttpUtility]::UrlEncode($webUrl)
#build the URI
$uri = New-Object System.UriBuilder
$uri.Scheme = "odopen"
$uri.Host = "sync"
$uri.Query = "siteId=$siteId&webId=$webId&listId=$listId&userEmail=$userEmail&webUrl=$webUrl&listTitle=$listTitle&webTitle=$webTitle"
#launch the process from URI
Write-Host $uri.ToString()
start-process -filepath $($uri.ToString())
}
catch {
$errorMsg = $_.Exception.Message
}
if ($errorMsg) {
Write-Warning "Sync failed."
Write-Warning $errorMsg
}
else {
Write-Host "Sync completed."
while (!(Get-ChildItem -Path $syncPath -ErrorAction SilentlyContinue)) {
Start-Sleep -Seconds 2
}
return $true
}
}
#endregion
#region Main Process
try {
#region Sharepoint Sync
[mailaddress]$userUpn = cmd /c "whoami/upn"
$params = #{
#replace with data captured from your sharepoint site.
siteId = "{11111111-1111-1111-11111111111111111}"
webId = "{22222222-2222-2222-22222222222222222}"
listId = "{33333333-3333-3333-33333333333333333}"
userEmail = $userUpn
webUrl = "https://somecompany.sharepoint.com/sites/graphics"
webTitle = "graphics"
listTitle = "Documents"
}
$params.syncPath = "$(split-path $env:onedrive)\$($userUpn.Host)\$($params.webTitle) - $($Params.listTitle)"
Write-Host "SharePoint params:"
$params | Format-Table
if (!(Test-Path $($params.syncPath))) {
Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
$sp = Sync-SharepointLocation #params
if (!($sp)) {
Throw "Sharepoint sync failed."
}
}
else {
Write-Host "Location already syncronized: $($params.syncPath)" -ForegroundColor Yellow
}
#endregion
}
catch {
$errorMsg = $_.Exception.Message
}
finally {
if ($errorMsg) {
Write-Warning $errorMsg
Throw $errorMsg
}
else {
Write-Host "Completed successfully.."
}
}
#endregion
But I need do this for several SharePoint Sites, but I'd like to avoid having to run 10 different PowerPoint Scripts, if possible.
What I've tried:
I've made an array where I've defined the variables for all the sites, like this (with the correct data):
$params = #(
[pscustomobject]#{
siteId = "SiteID";
webId = "webId";
listId = "listId";
userEmail = $userUpn;
webUrl = "webUrl";
webTitle = "webTitle";
listTitle = ""Documents"
}
[Repeated for each Site]
)
I've then altered this part of the original code, to do a ForEach loop:
#region Main Process
try {
#region Sharepoint Sync
[mailaddress]$userUpn = cmd /c "whoami/upn"
$params | ForEach-Object {
$params.syncPath = "$(split-path $env:onedrive)\$($userUpn.Host)\$($params.webTitle) - $($Params.listTitle)"
Write-Host "SharePoint params:"
$params | Format-Table
if (!(Test-Path $($params.syncPath))) {
Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
$sp = Sync-SharepointLocation #params
if (!($sp)) {
Throw "Sharepoint sync failed."
}
}
else {
Write-Host "Location already syncronized: $($params.syncPath)" -ForegroundColor Yellow
}
}
#endregion
}
But it's not working as expected: Only the first Site in my Array is synced.
I'm a PowerShell beginner, so please help me: What am I doing wrong?
Thanks!
When looping through all the objects inside the $params array using a ForEach-Object, the object that you want to reference will be $_ .. not $params. So, where you are referencing $params.webTitle, etc., you should be referencing $_.webTitle, $_.listTitle, etc.
If you're new to Powershell, I would recommend you setting a variable like $paramObj for each instance using foreach ($parmObj in $params) {...} to make it clear what you are referencing, making the code look like:
# replaces the ForEach-Object
ForEach ($paramObj in $params) {
Write-Host "SharePoint params:"
$paramObj | Format-Table
# i didn't see a syncPath in your $params custom object.. better if you set a local variable
$syncPath = "$(split-path $env:onedrive)\$($userUpn.Host)\$($paramObj.webTitle) - $($paramObj.listTitle)"
if (!(Test-Path $($syncPath))) {
Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
$sp = Sync-SharepointLocation #paramObj
if (!($sp)) {
Throw "Sharepoint sync failed."
}
}
else {
Write-Host "Location already syncronized: $syncPath" -ForegroundColor Yellow
}
}
Related
Trying to use PowerShell to capture the running status of the "Nessus Essentials" software product. Simply trying to capture product status: running, not running, or other. Getting the below error each time. I've tried changing -like to -match and changing string [warn] [scanner] Not linked to a manager to various other shorter versions, with wildcards and without, to no avail. I still get several lines of an ugly error message when all I want is one line with the string Not linked to a manager returned to console with nothing beneath that.
Pertinent snippet working incorrectly:
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
The Error:
The Code:
Function Start-ProcessGetStreams {
[CmdLetBinding()]
Param(
[System.IO.FileInfo]$FilePath,
[string[]]$ArgumentList
)
$pInfo = New-Object System.Diagnostics.ProcessStartInfo
$pInfo.FileName = $FilePath
$pInfo.Arguments = $ArgumentList
$pInfo.RedirectStandardError = $true
$pInfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pInfo.CreateNoWindow = $true
$pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $pInfo
Write-Verbose "Starting $FilePath"
$proc.Start() | Out-Null
Write-Verbose "Waiting for $($FilePath.BaseName) to complete"
$proc.WaitForExit()
$stdOut = $proc.StandardOutput.ReadToEnd()
$stdErr = $proc.StandardError.ReadToEnd()
$exitCode = $proc.ExitCode
Write-Verbose "Standard Output: $stdOut"
Write-Verbose "Standard Error: $stdErr"
Write-Verbose "Exit Code: $exitCode"
[PSCustomObject]#{
"StdOut" = $stdOut
"Stderr" = $stdErr
"ExitCode" = $exitCode
}
}
Function Get-NessusStatsFromStdOut {
Param(
[string]$stdOut
)
$stats = New-Object System.Collections.Hashtable
$StdOut -split "`r`n" | % {
if($_ -like "*:*") {
$result = $_ -split ":"
$stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]","_").ToLower(),$result[1].Trim())
}
}
Return $stats
}
Function Get-DateFromEpochSeconds {
Param(
[int]$seconds
)
$utcTime = (Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($seconds))
Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"
}
Try {
$nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus\nessuscli.exe" -ErrorAction Stop
} Catch {
Throw "Cannot find NessusCli.exe"
}
Write-Host "Getting Agent Status..."
$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"
If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
Throw "No Data Returned from NessusCli"
} elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
Throw "StdErr: $($agentStatus.StdErr)"
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
} elseif(-not($agentStatus.stdOut -like "*Running: *")) {
Throw "StdOut: $($agentStatus.StdOut)"
} else {
$stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut
If($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }
If($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }
If($stats.last_scanned -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_scanned }
}
$stats | Out-Host
Note: Code above is courtesy of here, I've only made a change to the path of Nessus, and I am adding the attempt to capture that it's not connected to a manager.
Modify your code so that it separates standard output from error and so that it handles each line separately.
The following is how to capture standard output (excluding else statements and error handling) of a program (according to your $Proc variable)
if ($proc.Start())
{
while (!$proc.StandardOutput.EndOfStream)
{
$StreamLine = $proc.StandardOutput.ReadLine()
if (![string]::IsNullOrEmpty($StreamLine))
{
# TODO: Duplicate code in this scope as needed or rewrite to use multiline regex
$WantedLine = [regex]::Match($StreamLine, "(?<wanted>.*Not linked to a manager.*)")
$Capture = $WantedLine.Groups["wanted"]
if ($Capture.Success)
{
Write-Output $Capture.Value
}
}
}
}
After that deal with error output separately:
$StandardError = $Proc.StandardError.ReadToEnd()
if (![string]::IsNullOrEmpty($StandardError))
{
# Or use Write-Error
Write-Output $StandardError
}
I am trying to adapt a script that syncs an entire document library.
What I want to achieve is syncing just a specific folder within a document library.
IE: User 1 has no permissions to the site or root folder of the document library, but has contribute permission to \site\documents\Folder1\Folder2
Is there a way to script it to sync just folder 2?
When I use the attached script, I get "We can't sync this folder right now" as User1 does not have access to the site or root of the document library.
#region Functions
function Sync-SharepointLocation {
param (
[guid]$siteId,
[guid]$webId,
[guid]$listId,
[mailaddress]$userEmail,
[string]$webUrl,
[string]$webTitle,
[string]$listTitle,
[string]$syncPath
)
try {
Add-Type -AssemblyName System.Web
#Encode site, web, list, url & email
[string]$siteId = [System.Web.HttpUtility]::UrlEncode($siteId)
[string]$webId = [System.Web.HttpUtility]::UrlEncode($webId)
[string]$listId = [System.Web.HttpUtility]::UrlEncode($listId)
[string]$userEmail = [System.Web.HttpUtility]::UrlEncode($userEmail)
[string]$webUrl = [System.Web.HttpUtility]::UrlEncode($webUrl)
#build the URI
$uri = New-Object System.UriBuilder
$uri.Scheme = "odopen"
$uri.Host = "sync"
$uri.Query = "siteId=$siteId&webId=$webId&listId=$listId&userEmail=$userEmail&webUrl=$webUrl&listTitle=$listTitle&webTitle=$webTitle"
#launch the process from URI
Write-Host $uri.ToString()
start-process -filepath $($uri.ToString())
}
catch {
$errorMsg = $_.Exception.Message
}
if ($errorMsg) {
Write-Warning "Sync failed."
Write-Warning $errorMsg
}
else {
Write-Host "Sync completed."
Exit
while (!(Get-ChildItem -Path $syncPath -ErrorAction SilentlyContinue)) {
Start-Sleep -Seconds 2
}
return $true
}
}
#endregion
#region Main Process
try {
#region Sharepoint Sync
[mailaddress]$userUpn = cmd /c "whoami/upn"
$params = #{
#replace with data captured from your sharepoint site.
siteId = ""
webId = ""
listId = ""
userEmail = $userUpn
webUrl = ""
webTitle = ""
listTitle = ""
}
$params.syncPath = "$(split-path $env:onedrive)\$($userUpn.Host)\$($params.webTitle) - $($Params.listTitle)"
Write-Host "SharePoint params:"
$params | Format-Table
if (!(Test-Path $($params.syncPath))) {
Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
$sp = Sync-SharepointLocation #params
if (!($sp)) {
Throw "Sharepoint sync failed."
}
}
else {
Write-Host "Location already syncronized: $($params.syncPath)" -ForegroundColor Yellow
Exit
}
#endregion
}
catch {
$errorMsg = $_.Exception.Message
}
finally {
if ($errorMsg) {
Write-Warning $errorMsg
Throw $errorMsg
}
else {
Write-Host "Completed successfully.."
Exit
}
}
#endregion
I am writing a powershell script to manage our local administrator accounts using a csv file.
#variable to store the data in data.csv
$userobjects = Import-CSV C:-data.csv
function main-list{
Write-Host "--------------------------------------"
Write-Host "Windows Powershell Account Manager"
Write-Host "--------------------------------------"
Write-Host "1 - Change Name"
Write-Host "2 - Disabled Account"
Write-Host "3 - Delete User"
Write-Host "4 - Exit"
[int]$action = Read-Host "Enter the menu number from above"
if ($action -eq 1){change-name}
if ($action -eq 2){disable-account}
if ($action -eq 3){delete-user}
if ($action -eq 4){cls; break}
}
function change-name
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
# Rename
if (($user.Account -ne $user.Rename) -and ($user.Rename -ne '' ))
{
#Write-Host "old name :"$FileHostname"/"$FileAccount "-> new name :"$FileHostname"/"$FileNewname
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://$connection")
if ($accName.path -eq "WinNT://"+$connection+"")
{
$accName.psbase.Rename($FileNewname)
Write-Host "Account(s) renamed"
$user.Account = $user.Rename
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
$user.Account = $user.Rename
$userobjects | export-csv C:-data.csv -notype
}
}
Write-Host "--------------------------------------"
main-list
}
function disable-account
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
if ($user.Disable -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
if ($accName.UserFlags -eq '515')
{
Write-Host "Account :"$connection "is already disabled"
}
else
{
$accName.description = "Account disabled"
$accName.UserFlags = 2
$accName.setinfo()
Write-Host "Account(s) disabled"$connection
}
}
}
Write-Host "--------------------------------------"
main-list
}
function delete-user
{
foreach ($user in $userobjects)
{
#Assign the content to variables
$FileHostname = $user.Host
$FileAccount = $user.Account
$FileNewname = $user.Rename
$FileDisable = $user.Disable
$FileDelete = $user.Delete
#Delete
if ($user.Delete -eq 'yes')
{
$connection = $FileHostname+"/"+$FileAccount
$accName = [ADSI]("WinNT://"+$connection+"")
$accName.delete("user",$accName.name)
#Write-Host $connection deleted
}
else
{
Write-Host "Account name :"$connection "can't be found on the host"
}
}
}
}
$userobjects | export-csv C:-\data.csv -notype
main-list
I don't really know why I have this message when I am trying to use the delete function : "Unknown name", it is like it doesn't find the local account to delete it but I am not sure. However, It works perfectly when I want to rename or disable accounts.
My data file looks like that
http://www.noelshack.com/2016-05-1454622367-capture.png
I will post the real message when I will be back to work tomorow.
Thank you for your help.
Quick skim... wouldn't this need to be used instead? I think your $accName.name would be using the machine name.
$accName.delete("user",$user.account)
You delete() the user from the computer, so your [adsi] object should bind to the computer and call Delete() on that instead:
# Just the machine name, nothing more:
$Machine = [ADSI]"WinNT://$FileHostname"
# Now delete the user account from the machine
$Machine.Delete('user',$FileAccount)
I have the following PowerShell script to run a quick HitmanPro scan on computers. I have deployed this script through GFI RMM and while it works, I need to pass it domain administrator information.
$HitmanParameters = "/scanonly /quick /noinstall /quiet"
$AgentPath = (${env:ProgramFiles(x86)}, ${env:ProgramFiles} -ne $null)[0]
if (Test-Path "$AgentPath\Advanced Monitoring Agent") {
$AgentPath="$AgentPath\Advanced Monitoring Agent"
} elseif (Test-Path "$AgentPath\Advanced Monitoring Agent GP") {
$AgentPath="$AgentPath\Advanced Monitoring Agent GP"
} else {
Write-Host "Agent Path Not Found"
}
if (-not (Test-Path "$AgentPath\HitmanPro")) {
Write-Host "Creating Hitman Folder"
[system.io.directory]::CreateDirectory("$AgentPath\HitmanPro")
}
$HitmanParameters = "$HitmanParameters /log=""$AgentPath\HitmanPro\results.txt"""
if (-not (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe")) {
Write-Host "HitmanPro Not found"
if ($(Get-WmiObject -Query "SELECT * FROM Win32_Processor WHERE AddressWidth='64'")) {
$HMPURL = "http://dl.surfright.nl/HitmanPro_x64.exe"
} else {
$HMPURL = "http://dl.surfright.nl/HitmanPro.exe"
}
Write-Host "Downloading $HMPURL ..."
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($HMPURL,"$AgentPath\HitmanPro\HitmanPro.exe")
if (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe") {
Write-Host "Download Complete!"
} else {
Write-Host "Error Downloading Hitman Pro"
}
}
if (Test-Path "$AgentPath\HitmanPro\HitmanPro.exe") {
Write-Host "Running HitmanPro Scan..."
Write-Host "HitmanPro.exe $HitmanParameters"
Start-Process -FilePath "$AgentPath\HitmanPro\HitmanPro.exe" -ArgumentList "$HitmanParameters" -NoNewWindow -Wait
If (Test-Path "$AgentPath\HitmanPro\results.txt") {
$data = Get-Content -Encoding Unicode "$AgentPath\HitmanPro\results.txt"
remove-item "$AgentPath\HitmanPro\results.txt"
foreach ($line in $data) {
If($line.contains("Threats")) {
$Infections = [int] $line.Split(":")[1]
If($Infections -eq 0) {
Write-Host "No Infections Found"
$data
exit 0
break
} Else {
Write-Host "Infections Found!"
$data
exit 1000
break
}
} #If Line contains Threats
} #ForEach
} Else {
Write-Host "No Logfile Found"!
} #LogFile Found
} Else {
Write-Host "HitmanPro Still Not Found!"
}#HitmanPro Found
I have the following code which adds a webpart, but i need some way to delete all the webparts before this runs. Anybody know how to do this? I have tried multiple ways, but am brand new to powershell and sharepoint and have no idea what i am doing.
$wpm = $file.GetLimitedWebPartManager([Microsoft.SharePoint.Client.WebParts.PersonalizationScope]::Shared)
$sortedNodes = $pageXml.Module.File.AllUsersWebPart | sort { $_.WebPartZoneID, [int] $_.WebPartOrder }
write-host $sortedNodes
write-host $sortedNodes.Count
foreach ($webPartXml in $sortedNodes)
{
$zoneId = $webPartXml.WebPartZoneID
$zoneIndex = $webPartXml.WebPartOrder
$xml = $webPartXml.InnerText
$wpd = $wpm.ImportWebPart($xml)
$wpd = $wpm.AddWebPart($wpd.WebPart, $zoneId, $zoneIndex)
"Adding a web part to the [$zoneId] zone, [$zoneIndex] position..."
try
{
Submit-ExecuteQuery $context
}
catch
{
Write-Host "The following error occurred while trying to add the web part: $($_.Exception.Message)" -ForegroundColor Red
}
}
Please try the following:
$wpm = $file.GetLimitedWebPartManager([Microsoft.SharePoint.Client.WebParts.PersonalizationScope]::Shared)
<# Remove All Webparts - Begin #>
foreach ($webPart in $wpm.WebParts)
{
$wpdD = New-Object Microsoft.SharePoint.Client.WebParts.WebPartDefinition
$context.Load($webPart)
$wpdD = $webPart
$wpdD.DeleteWebPart();
try
{
Submit-ExecuteQuery $context
}
catch
{
Write-Host "The following error occurred while trying to add the web part: $($_.Exception.Message)" -ForegroundColor Red
}
}
<# Remove All Webparts - End #>
$sortedNodes = $pageXml.Module.File.AllUsersWebPart | sort { $_.WebPartZoneID, [int] $_.WebPartOrder }
write-host $sortedNodes
write-host $sortedNodes.Count
foreach ($webPartXml in $sortedNodes)
{
$zoneId = $webPartXml.WebPartZoneID
$zoneIndex = $webPartXml.WebPartOrder
$xml = $webPartXml.InnerText
$wpd = $wpm.ImportWebPart($xml)
$wpd = $wpm.AddWebPart($wpd.WebPart, $zoneId, $zoneIndex)
"Adding a web part to the [$zoneId] zone, [$zoneIndex] position..."
try
{
Submit-ExecuteQuery $context
}
catch
{
Write-Host "The following error occurred while trying to add the web part: $($_.Exception.Message)" -ForegroundColor Red
}
}