I'm playing with some PowerShell code to dynamically generate AD security groups and then apply them to folders on a network share, but having issues with resolving the newly created group.
Consider this:
import-module activedirectory
for ($i = 0; $i -lt 10; $i++) {
$group = New-ADGroup -Path "OU=Groups,OU=Department,DC=Domain,DC=Network" -Name "z-test-group-$i" -GroupScope DomainLocal -GroupCategory Security -PassThru
$acl = Get-Acl C:\Temp
$permission = $group.SID,"FullControl","Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
$acl | Set-Acl C:\Temp
}
Which works fine.
However, if I change the folder to a network folder, such as G:\Temp, or \\domain.network\DFS\GroupShare\Temp, I get a 'Method failed with unexpected error code 1337'.
I tired using SetACL.exe and received a similar error:
C:\Temp\SetACL.exe -on "\\domani.network\dfs\GroupShare\Temp" -ot file -actn ace -ace "n:$GroupSID;p:full;s:y"
SetACL finished with error(s):
SetACL error message: The call to SetNamedSecurityInfo () failed
Operating system error message: The security ID structure is invalid.
INFORMATION: Processing ACL of: <\\?\UNC\domain.network\dfs\GroupShare\Temp>
If I wait say 10 to 20 seconds, and run the Set-ACL (or SetACL.exe) portion of the code again, it completes successfully.
At first I thought this was related directly to the domain controllers (4 of them which are a mix of 2003 and 2008 R2), but the fact that it worked fine on local folders was intriguing (and annoying).
I did a Wireshark trace during the execution of the code on a local folder and then a network folder. The main difference is when trying to apply the ACLs to the network folder I see LDAP lookups and (amongst other things) the following SMB response:
NT Trans Response, FID: 0x0040, NT SET SECURITY DESC, Error: STATUS_INVALID_SID
Which I assume is what causes my Set-ACL command to fail.
The underlying network filesystem is EMC Celerra 6.0.xx. I am very unfamiliar with this technology, however from what I understand it holds some kind of SID cache which would explain the above error (it doesn't yet know of the new group even though AD does).
So I guess there are two questions:
Is there any way around this (PowerShell/C# ect) that doesn't
involve sleeping/waiting? IE, set the ACL even though the SID is
invalid?
If EMC Celerra is the issue (I assume it is), is there any
way I can force it to update its 'SID cache' or whatever it may be?
I have read various articles about this issue, but none seem to have an effective resolution (or work for me).
Thanks for your help.
Rhys.
If the issue is just the delay involved in waiting for the cache to update blocking other work the script needs to be doing you could ship that off to a background job and let your main script go on to other things.
Figured it out!
Modified the acl.mappingErrorAction on our EMC Celerra NAS.
Was set to 0, updated it to 1.
server_param server_2 -facility cifs -modify acl.mappingErrorAction -value 1
Now we have no issues in setting the newly created security group into the ACLs for the folder on a network share (no delays).
Info: acl.mappingErrorAction
Defines the rules for unknown mapping between security, user, and group identifiers (SID/UID/GID) on ACL settings.
Two kinds of errors might occur:
The SID set in the ACL is unknown to the domain controllers being used.
The username is not yet mapped to a UID/GID.
The bit list consists of four binary bits (bits 0 through 3, right to left). Each bit is 1 when set; otherwise 0.
Bit 0 (0001 or +1): Store unknown SID.
Bit 1 (0010 or +2): Store SID with no UNIX mapping.
Bit 2 (0100 or +4): Enable debug traces.
Bit 3 (1000 or +8): Do lookup only in cache (secmap or global SID cache or per connection SID cache).
Values: 0 – 15
Default: 0
Seems obvious enough now that I understand more about the underlying CIFS/ACL settings on the NAS then I ever wanted to know.
Rhys.
Related
$PrivateDrive = "Sharedrivepath1"
$ScanDrive = "ScanDrivePath2"
New-Item -Itemtype SymbolicLink -Path $PrivateDrive -Name ScanDrive -Value $ScanDrive
I am trying to create a shortcut from the ScanDrive to the PrivateDrive, I have a full filepath and have access to both locations.
These both exist.
But I get the error "New-Item : Symbolic Links are not supported for the specified path"
EDIT: This is how I declare my Private and Scan Drives
$SamaccountName = ($name).Givenname + '.' + ($name.Surname)
$PrivateDrive = '\\SERVER1\private\home folders\' + $SamaccountName
$ScanDrive = "\\SERVER2\Shares_2\" + $SamaccountName
The error message is PowerShell's, in response to the underlying CreateSymbolicLink() WinAPI function reporting error code 1 (INVALID_FUNCTION).
There are two possible causes that I'm aware of:
A configuration problem: R2R (Remote-to-Remote) symlink evaluation is disabled (which is true by default.
To query the current configuration, run the following:
fsutil behavior get SymLinkEvaluation
To modify the configuration, you must call from an elevated (run as admin) session. The following enables R2R symlink evaluation:
# Requires an ELEVATED session.
fsutil behavior set SymLinkEvaluation R2R:1
(Less likely) A fundamental limitation:
The remote link path (the target path too?) is not exposed vie one of the following technologies, which are the ones listed as supported in the linked WinAPI help topic:
Server Message Block (SMB) 3.0 protocol
SMB 3.0 Transparent Failover (TFO)
Resilient File System (ReFS)
start "odopen://sync/?siteId=$siteid17&webId=$webid17&listId=$listid17&userEmail=$upn&webUrl=$URL17&webtitle=$webtitle17&listtitle=$listtitle17"
How is it possible to run the following command inside Powershell without an appearing popup window or any userinteraction? I've tried adding /ArgumentList "/S", "/Background". Also tried with -WindowStyle Hidden at the end. Appreciate some help :)
Your command as-is basically says "Start the program that opens odopen:// (OneDrive) links" and can't really be given any silent style instructions. The proper way to configure this kind of thing is through OneDrive Group Policies, but we can cheat and set registry keys.
The link above goes into detail about how to configure group policy, but also tells us that the specific group policy setting to "Configure team site libraries to sync automatically" sets this registry key:
[HKCU\Software\Policies\Microsoft\OneDrive\TenantAutoMount]"LibraryName"="LibraryID"
And that your LibraryID is in this format, which looks familiar:
tenantId=xxx&siteId=xxx&webId=xxx&listId=xxx&webUrl=httpsxxx&version=1
So to put it in a script, I would use something like this, adapted from Nicola Suter's blog post here:
$tenantAutoMountRegKey = "HKLM:\SOFTWARE\Policies\Microsoft\OneDrive\TenantAutoMount"
$autoMountTeamSitesList= #{
#Enter your SharePoint libraries to configure here as key/value pairs
MySharePoint="odopen://sync/?siteId=$siteid17&webId=$webid17&listId=$listid17&userEmail=$upn&webUrl=$URL17&webtitle=$webtitle17&listtitle=$listtitle17"
}
# Check if the key exists and create if missing:
if (-not (Test-Path $tenantAutoMountRegKey)){ New-Item -Path $tenantAutoMountRegKey -Force }
# Add the sites for automatic mounting
$autoMountTeamSitesList | Set-ItemProperty -Path $tenantAutoMountRegKey -Name $_.Key -Value $_.Value
This generally takes effect the next time a user signs into OneDrive, though Microsoft warns it may take up to 8 hours to start syncing (Keeps hundreds of users from syncing the same library at the same time)
TL;DR: You cannot.
Using odopen will always show sign-in window (as stated here: https://learn.microsoft.com/en-us/onedrive/deploy-on-windows#help-users-sign-in), what you can do is only populate it with data, which is what you are already doing.
If you want to do it silently, there is documentation about it: https://learn.microsoft.com/en-us/onedrive/use-silent-account-configuration
I want to switch 2 files in the SYSVOL Folder. For that I need to Invoke-Command a script on a Domain Controller from our schedule server.
$Server = Get-ADDomainController | select Name
Invoke-Command -ComputerName $Server.Name -ScriptBlock {
$Path = "c:\Windows\SYSVOL\sysvol\domain.com\scripts\Folder"
$Source = "$Path\backgrounddefault1.JPG"
$trg = "$Path\backgrounddefault.JPG"
Copy-Item -Path $Source -Destination $trg -Force
}
However if I do not promote the Service Account to Domain Admin, the script will get an access denied.
Are there any other ways I could do this, or other groups that give him that specific right?
The group is called "Remote Management Users". Obviously, however, you'll also need permissions on the folder. Create a new group for those rights specifically, and make it a member of RMU. Make the service account a member of the new group. (Note that none of this is specific to DCs.)
If you wanted to do this without changing any permissions on a Sysvol subdirectory, the cleanest thing I can think of would be to create a scheduled task on the DC running under local system that performs only this operation, and grant the service account permission to start this task. (There is no interface for this, but you can manipulate the SecurityDescriptor of what you get with Get-ScheduledTask; see this question, for example).
If this task needs parameters/input, it gets trickier since you'll need to supply these in a file somehow. Because that task effectively has domain admin permissions, you'd have to take very good care to check your inputs and make sure the task has no exploitable vulnerabilities. Just tweaking the permissions on that one specific folder seems a lot easier and also safer to me.
Last but not least, when performing operations like these it's always worth investigating if what you're trying to do can't be done with Group Policy somehow, because it leaves a clear statement of intent (and an audit trail).
I'm fairly new to PowerShell and am running into a problem.
I want to do the following:
Get list of permissions/users on a single folder on a different server than where I am running my PowerShell window from.
Current command failing:
Get-acl -path "\\servername\folder"
Error Message:
Get-acl : Cannot find path '\\servername\folder' because it does not exist
Does this command only work on the local machine?
It turns out with the way permissions/authentications are setup in my environment prevented my code from working.
Here are the steps I took to verify if I could connect to the server:
Test-Path \\server\folder
This returned "False", which is why my code was breaking.
The work around I used was this:
#Step 1: remotely connect to server
Enter-PSSession -ComputerName servernamegoeshere
#Step 2: get list of permissions on folder and save to csv
get-acl E:\foldernamehere |
select -expand access |
export-csv C:\Users\usernamegoeshere\Documents\listofperms.csv |
#Step 3: close remote connection
Exit-PSSession
I still had to remote into the server and copy the csv to the location I wanted because again, any copy command to another server/share in PowerShell would not work due to permission/authentication issues.
This article explains authentication/permissions a bit better than I can:
http://blogs.technet.com/b/heyscriptingguy/archive/2012/11/14/enable-powershell-quot-second-hop-quot-functionality-with-credssp.aspx
Second way to do this with less code and not having to create a remote session thanks to user Ansgar Wiechers:
Invoke-Command -Computer server -ScriptBlock {get-acl E:\folder |
select -expand access } |
export-csv \\server\folder\accesslist.csv
With PowerShell, there are many ways to do one thing...I think this way is best/most simple! Thanks!
The command works on UNC paths as well, but UNC paths are slightly different from local paths. You need an access point to enter the file system of a remote host. For SMB/CIFS access (via UNC paths) that access point is a shared folder, so you need a path \\server\share or \\server\share\path\to\subfolder.
With an admin account you could use the administrative shares (e.g. \\server\C$\Users\Administrator), otherwise you need to create a share first.
We run some processes in a distributed computing environment. Processes on one machine need to communicate information with processes on other machines. One of those piecies of information is the location of certain files. Thus, a process on one machine may have put information into a particular file on a particular network share, and it needs to communicate the location to a process on another machine.
We have no problem with the communication part. The problem is with determining the "location" information that a machine need to disseminate. File paths involving drive mappings are clearly useless: different machines will have differing drive mappings. Thus, what we need to communicate it the full UNC path name.
For the most part, we can obtain that information easily. One place where we are having problems is in a powershell script that needs to obtain this information. Currently, we use the following code:
$l_logicalDisk = Gwmi Win32_LogicalDisk -filter "DeviceID = '$l_currentDrive'"
if ( $l_logicalDisk.DriveType -eq 4 )
{
$l_base = $l_logicalDisk.ProviderName
}
and $l_base provides the \\computername\share information. However, in certain circumstances, this fails. At times, for some unknown reason, a mapped drive will appear as "Disconnected Network Drive" in Explorer.exe, even though the drive and all its files are accessible. (In fact, the script that is running is even located on the supposed "Disconnected Network Drive".) In this situation, the ProviderName field of the logical disk information is blank. Nothing seems to flip the status from "Disconnected Network Drive", nor have I found any way to update the ProviderName information.
So, does anyone know either (1) how to "reconnect" a disconnected network drive from within powershell or (2) how in Powershell to obtain the UNC path information for a directory in a more reliable method that outlined above? Thanks.
You can always ask the registry, this should work on disconnected drives (where $DrvLtr equals the desired network mapped drive letter such as Z or M):
Pushd
cd HKCU:
$UNC=(gci network|?{$_.Name -match "$DrvLtr"}|%{Get-ItemProperty -Path $_}).RemotePath
Popd
$UNC should then be a string with a value like "\Server01\FileShare$" which I think is what you're going for. Then you can just do a
$Path.Replace("$DrvLtr`:",$UNC)
And you're all set