Error when executing PowerShell script for SharePoint Online - powershell

So, i'm trying to run this SPO PowerShell script that microsoft provides in this link:
https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/export-spouserinfo?view=sharepoint-ps on the "example 2". However, when i try to run the script on PowerShell ISE, i get the following error: "Parameter missing for 'Output Folder' argument. Specify a 'System.String' type parameter and try again." I tried to change the arguments, input my site collection, creating a .csv file on the folder, but nothing changes this error message, what am i doing wrong?
Here is the code i'm using:
$sites = Get-SPOSite -IncludePersonalSite $true
$user = "xxxxxx#domain.com"
foreach ($site in $sites)
{
Export-SPOUserInfo -LoginName $user -site $site.Url -OutputFolder
"D:"
}
Thanks in advance!

Writing to the root of a drive is really not a best practice. Always use a folder of the root, unless there is a very valid reason to put a file there. Yet, that is not your use case as presented.
$sites = Get-SPOSite -IncludePersonalSite $true
$user = "xxxxxx#domain.com"
foreach ($site in $sites)
{
Export-SPOUserInfo -LoginName $user -site $($site.Url) -OutputFolder 'D:\SPOSiteData'
}
Your string must be all on one line if not properly terminated for multi-line. For example, using PowerShell Splatting
about_Splatting - PowerShell | Microsoft Docs
$ExportSPOUserInfoSplat = #{
LoginName = $user
site = $($site.Url)
OutputFolder = 'D:\SPOSiteData'
}
Export-SPOUserInfo #ExportSPOUserInfoSplat
Te line wrapping, which it seems you copied and pasted, is that way because of page space not a code requirement.

Related

Create azure dynamic group from azure functions powershell

I am trying to create an azure function that has to create azure dynamic group when i execute the function from MS flow. I am using below code for this purpose.
$groupName = $Request.Query.Name
$groupDesc = $Request.Query.Desc
$domainnames = $Request.Query.DomainName
$dynamicrule = ""
Foreach($domainname in $domainnames.Split(";"))
{
$dynamicrule = $dynamicrule + "(user.userPrincipalName -contains ""_$domainname"") or";
}
$dynamicrule = $dynamicrule -replace ".{2}$"
$dynamicrule = $dynamicrule + "and (user.objectId -ne null)";
New-AzureADMSGroup -DisplayName $groupName -Description $groupDesc -MailEnabled $False -MailNickName "group" -SecurityEnabled $True -GroupTypes "DynamicMembership" -MembershipRule $dynamicrule -MembershipRuleProcessingState "On"
When i execute the above command, i am getting below error messgae.
ERROR: The term 'New-AzureADMSGroup' is not recognized as the name of a cmdlet, function, script file, or operable program.Check the spelling of the name, or if a path was included, verify that the path is correct and try again.Exception :Type : System.Management.Automation.CommandNotFoundExceptionErrorRecord
Can sombody please help me on how can i create dynamic groups using azure function app.
Thanks,
Venu
From the error message, you did not install AzureAD powershell module in your function app. And if you want to create a dynamic group, you need to use the -MembershipRule parameter, it is just available in the preview version i.e. AzureADPreview module. Though the doc looks like the parameter is available in AzureAD, but per my test, it is not available.
Actually it is easy to solve the issue, but if you want to create a dynamic group with New-AzureADMSGroup, there will be a few follow-up issues, you could follow the steps below.
1.Navigate to the function app in the portal -> Identity -> enable the system-assigned identity(MSI) for your app.
2.Navigate to App files -> host.json -> make sure the managedDependency is Enabled.
{
"version": "2.0",
"managedDependency": {
"Enabled": true
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
In the requirements.psd1, add the AzureADPreview like below, then it will install the AzureADPreview module for you automatically.
#{
'Az' = '5.*'
'AzureADPreview' = '2.0.2.129'
}
In the profile.ps1, remove all the things and add the lines below, this is used to solve the issue related to AzureAD powershell in function, without it, you will get an error, details here.
$64bitPowerShellPath = Get-ChildItem -Path $Env:Windir\WinSxS -Filter PowerShell.exe -Recurse -ErrorAction SilentlyContinue | Where-Object {$_.FullName -match "amd64"}
$env:64bitPowerShellPath=$64bitPowerShellPath.VersionInfo.FileName
3.If you want to use New-AzureADMSGroup to create group in Azure AD, you need the permission in Microsoft Graph, in this case, we use MSI to auth, so use the commands below to give the permission to your MSI.
Run the commands below in local with the Global admin user account, replace <functionapp-name>:
Connect-AzureAD
$MSI = (Get-AzureADServicePrincipal -Filter "displayName eq '<functionapp-name>'")
$MSGraphAppId = "00000003-0000-0000-c000-000000000000"
$GraphServicePrincipal = Get-AzureADServicePrincipal -Filter "appId eq '$MSGraphAppId'"
$PermissionName = "Group.ReadWrite.All"
$AppRole = $GraphServicePrincipal.AppRoles | Where-Object {$_.Value -eq $PermissionName -and $_.AllowedMemberTypes -contains "Application"}
New-AzureADServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $GraphServicePrincipal.ObjectId -Id $AppRole.Id
4.After step 2, navigate to the kudu(in the Advanced Tools blade of the function app) -> data -> ManagedDependencies -> click the file with the format like 201208083153165.r(choose the newest one via the Modified time) -> check if the AzureADPreview module was installed successfully like below.
5.After the module was installed, in your function code, use the lines below, in my sample, I use this sample to test directly, you could change the code depends on your requirements, remember to replace 201208083153165.r with yours in step 4, it works fine on my side.
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
$body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
if ($name) {
$body = "Hello, $name. This HTTP triggered function executed successfully."
}
$script = {
if ($env:MSI_SECRET) {
Disable-AzContextAutosave -Scope Process | Out-Null
Connect-AzAccount -Identity
}
$context = Get-AzContext
$graphtoken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token
$aadtoken = (Get-AzAccessToken -ResourceUrl "https://graph.windows.net").Token
Import-Module D:\home\data\ManagedDependencies\201208083153165.r\AzureADPreview
Connect-AzureAD -AccountId $context.Account -TenantId $context.Tenant -MsAccessToken $graphtoken -AadAccessToken $aadtoken
New-AzureADMSGroup -DisplayName "joyd1" -Description "Dynamic group created from PS" -MailEnabled $False -MailNickName "group" -SecurityEnabled $True -GroupTypes "DynamicMembership" -MembershipRule "(user.department -contains ""Marketing"")" -MembershipRuleProcessingState "On"
}
&$env:64bitPowerShellPath -WindowStyle Hidden -NonInteractive -Command $Script
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
Check the group in the portal:

Create printers from an imported csv file to multiple print servers

I have been working with this script and have successfully grabbed info from a .csv file and added it to one print server.
Right now I have the print server hard coded in the script and it allows me to add multiple print servers into the script, but I would like to add the print servers to a column in my .csv file and read from there to eliminate the static servers in the code. Here is what I have:
The second part I am struggling with is publishing and not publishing printers ( listing in AD or not ) I was thinking of adding another column called published. Then creating an if/then to publish or not publish**
foreach ($server in #("printserver1")) {
foreach ($printer in #(Import-Csv C:\PrinterList.csv)) {
Add-PrinterPort -ComputerName $server -Name $printer.IPAddress -PrinterHostAddress $printer.IPAddress
Add-Printer -ComputerName $server -Name $printer.Printername -DriverName $printer.Driver -PortName $printer.IPAddress -Comment $printer.Comment -Location $printer.Location -Shared -ShareName $printer.Printername -Published
}
}
If PrinterList.csv contains a column called Publish with False or True as possible values, you can do the following:
foreach ($printer in (Import-Csv C:\PrinterList.csv)) {
$Params = #{ ComputerName = $server
Name = $printer.Printername
DriverName = $printer.Driver
PortName = $printer.IPAddress
Comment = $printer.Comment
Location = $printer.Location
ShareName = $printer.Printername
}
Add-Printer #Params -Shared -Published:([bool]::Parse($printer.Publish))
}
Since Publish is a [switch] parameter, you can use the syntax -Publish:$true or -Publish:$false. The Parse() method parses a string value into a boolean value.
$Params Splatting is not necessary here. It just provides a bit more readability.
Alternatively, [System.Convert]::ToBoolean($printer.Publish) has the same result in the proposed scenario but does offer more flexibility as [System.Convert]::ToBoolean(0) returns False and [System.Convert]::ToBoolean(1) returns True.

Setting the "Description" on a Document Library using PnP PowerShell for SharePoint Online

I am trying to set the description on a Document Library in SharePoint Online using the PnP-PowerShell Commands, but it seems to be very intermittent in working, so I wanted to check what the correct way to do it is?
I create a new library with:
New-PnPList -Template DocumentLibrary -Title "TempLibrary"
Then try to set the Description with:
$l = Get-PnPList -Identity TempLibrary
$l.Description = "My Description Here"
Now clearly that doesn't work since I need to send the changes back with CSOM I assume?
So then I tried the following:
$ctx = Get-PnPContext
$l = Get-PnPList -Identity TempLibrary
$l.Description = "My Description Here"
$ctx.ExecuteQuery()
But this still didn't seem to work.
Any thoughts anyone has on how to do this reliably would be greatly appreciated.
Many thanks,
D.
UPDATE
Eurgh... This seems to work, but is this right? Is it expected? Doesn't feel very PowerShell like...
New-PnPList -Title "Test5" -Template DocumentLibrary
$t = Get-PnPList -Identity Test5
$ctx.Load($t)
$ctx.ExecuteQuery()
$t.Description = "Test5 Description"
$t.Update()
$ctx.ExecuteQuery()
Without loading the list you will not be able to set the description or other properties so the code is correct.
$ctx.Load($t)
Why do you think this is not PS like? :) Curious...
Use the following script. Hope it helps.
Add - PSSnapin Microsoft.SharePoint.PowerShell
function CreateList($spWeb, $listName)
{
$spTemplate = $spWeb.ListTemplates["Document Library"]
$spListCollection = $spWeb.Lists
$spListCollection.Add($listName, $listName, $spTemplate)
}
Function SetDescription($spWeb, $listName)
{
$path = $spWeb.url.trim()
$spList = $spWeb.GetList("$path/Lists/$listName")
$spList.Description = "--Your Desired Description--"
$spList.Update()
}
$siteCollectionUrl = "--Your Site Collection Url--"
$listName = "--Your Desired List Name--"
$spWeb = Get - SPWeb - Identity $siteCollectionUrl
CreateList $spWeb $listName
SetDescription $spWeb $listName

How to test writing to a file share path using credential?

I have an array of Credential objects and I would like to test that these credentials have permissions to write a file to a file share.
I was going to do something like
$myPath = "\\path\to\my\share\test.txt"
foreach ($cred in $credentialList)
{
"Testing" | Out-File -FilePath $myPath -Credential $cred
}
but then I discovered that Out-File doesn't take Credential as a parameter. What's the best way to solve this?
You can use New-PSDrive:
$myPath = "\\path\to\my\share"
foreach ($cred in $credentialList)
{
New-PSDrive Test -PSProvider FileSystem -Root $myPath -Credential $Cred
"Testing" | Out-File -FilePath Test:\test.txt
Remove-PSDrive Test
}
Here is asituation where an old exe (net.exe) seems to do better than powershell...
I guess you could try to map a network drive with the credential provided then test to write a file to that drive :
$cred=get-credential
$pass=$cred.GetNetworkCredential().Password
net use q: \\servername\share $pass /user:$cred.username
Use this script taken from Microsofts TechNet Script Center : http://gallery.technet.microsoft.com/scriptcenter/Lists-all-the-shared-5ebb395a
It is a lot easier to alter to fit your needs then to start completely from scratch.
Open up ListSharedFolderPermissions.ps1, and find the three $Properties vars. add a line at the top of each one so you can tell which user your looking at, so it should now look like this:
$Properties = #{'Username' = $Credential.UserName
'ComputerName' = $ComputerName
. . . . . }
Next, add your new Username property to the select-object line (3 times) :
$Objs|Select-Object Username,ComputerName,ConnectionStatus,SharedFolderName,SecurityPrincipal, `
FileSystemRights,AccessControlType
Once youve added those small pieces in the six appropriate places your script is ready to use:
cd c:\Path\where\you\put\ps1\file
$permissions = #()
$myPath = "computername"
foreach ($cred in $credentialList)
{
$permissions += .\ListAllSharedFolderPermission.ps1 -ComputerName $myPath -Credential $cred
$permissions += " "
}
$permissions | Export-Csv -Path "C:\Permission.csv" -NoTypeInformation
Try using the Invoke-Command function. It will take a credential object and allow you to run an arbitrary script block under that command. You can use that to test out writing the file
Invoke-Command -ScriptBlock { "Testing" | Out-File $myPath } -Credential $cred
I think the Invoke-command approach should work. But if nothing works you can try the powershell impersonation module. It successfully impersonates a user for most Powershell commands without the -Credential switch.
A few ideas:
Create your own PowerShell Provider
Impersonate a user and then write to the share (not sure if possible in powershell)
Use net use d:... as #Kayasax has suggested
Use WScript.Network
I'm very interested in the PowerShell provider myself, but I decided to make something real quick so I went with using the WScript.Network library. I used a hash table to track whether a user would be "authenticated" or not.
$credentials = #() # List of System.Net.NetworkCredential objects
$authLog = #{}
$mappedDrive = 'z:'
$tmpFile = $mappedDrive, '\', [guid]::NewGuid(), '.tmp' -join ''
$path = [io.path]::GetPathRoot('\\server\share\path')
$net = new-object -comObject WScript.Network
foreach ($c in $credentials) {
if ($authLog.ContainsKey($c.UserName)) {
# Skipping because we've already tested this user.
continue
}
try {
if (Test-Path $mappedDrive) {
$net.RemoveNetworkDrive($mappedDrive, 1) # 1 to force
}
# Attempt to map drive and write to it
$net.MapNetworkDrive($mappedDrive, $path, $false, $c.UserName, $c.Password)
out-file $tmpFile -inputObject 'test' -force
# Cleanup
Remove-Item $tmpFile -force
$net.RemoveNetworkDrive($mappedDrive, 1)
# Authenticated.
# We shouldn't have reached this if we failed to mount or write
$authLog.Add($c.UserName, 'Authorized')
}
catch [Exception] {
# Unathenticated
$authLog.Add($c.UserName, 'Unauthorized')
}
}
$authLog
# Output
Name Value
---- -----
desktop01\user01 Authorized
desktop01\user02 Unauthorized

Powershell: An error occurred while enumerating through a collection: The specified directory service attribute or value does not e xist

I have been trying the following PowerShell script in several AD domain, but in one 2008 R2 domain it fails and I cannot find the reason for it:
PS D:\> Add-type -AssemblyName System.DirectoryServices.AccountManagement
PS D:\> $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
PS D:\> $Domain = $env:USERDOMAIN
PS D:\> $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $ct,$Domain
PS D:\> $user = System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($pc, "SamAccountName", "testuser")
PS D:\> $groups = $user.GetAuthorizationGroups()
D:\> $groups
Normally the script gives a list of groups but for this domain it gives the following error message (after the list of groups):
An error occurred while enumerating through a collection: The specified directory service attribute or value does not exist.
CategoryInfo:InvalidOperation(System.Director...ment.Principal]:FindResultEnumerator`1) [], Runtime
Exception
FullyQualifiedErrorId : BadEnumeration
Could this have anything to do with AD privileges or permission?
I this could happen for a few possible reasons:
While the groups are iterating, it tries to resolve the SID to an Active Directory object that does not exist. I would check out your Active Directory to make sure that there is no missing or broken AD users/groups. (Something like this error: Microsoft Connect - Calling Principal GetAuthorizationGroups Error)
This could also be because of a Foreign Security principal that can't get resolved (Like this: Foreign Security Groups in Active Directory)
Some possible solutions:
Ignore the errors i.e. start off with $ErrorActionPreference = "SilentlyContinue"
Try something like this:
(Very rough code as a starting point)
$searchRoot = New-Object System.DirectoryServices.DirectoryEntry
$adSearcher = New-Object System.DirectoryServices.DirectorySearcher
$adSearcher.SearchRoot = $searchRoot
$adSearcher.Filter = "(samAccountName=UserName)"
$adSearcher.PropertiesToLoad.Add("memberOf")
$samResult = $adSearcher.FindOne()
if($samResult)
{
$adAccount = $samResult.GetDirectoryEntry()
$groupMembership = $adAccount.Properties["memberOf"]
$groupMembership | foreach {
Write-Host $_
}
}