Benutzer mit den meisten Antworten
PowerShell zum Durchsuchen eines SharePoints (REST, CSOM)

Frage
-
Ich suche derzeit nach einer Möglichkeit, wie ich mit einem Script unseren Firmen-Sharepoint (O365 SharePoint Online) nach Dateien und Ordnern durchsuchen kann. Dies benötige ich als Grundlage für eine ganze Reihe von weiteren bereits existierenden Scripts, die nach dem vollständigen SharePoint-Umzug nicht mehr funktionieren werden, da diese über das FileSystemObject lediglich normale Netzlaufwerke durchsuchen können.
Das ganze muss also idealerweise in PowerShell umgesetzt werden.
Mein exemplarischer SharePoint ist Teil einer Collection und befindet sich unter "sites/collection3/sp1" (siehe unten). In dem Sharepoint haben die Fachabteilungen jeweils eine eigene Dokumentenbibliothek, bspw. "Production".
Hierzu habe ich mich zum Thema REST API belesen und scheitere leider schon beim Einstieg in die Thematik...
$TestQuery = Invoke-WebRequest -uri "https://mycompany.sharepoint.com/sites/collection3/sp1/Production" -Method Get -Credential "myemail@company.com"
Ausgabe von $TestQuery:
StatusCode : 200 StatusDescription : OK Content : <!-- Copyright (C) Microsoft Corporation. All rights reserved. --> <!DOCTYPE html> <html dir="ltr" class="" lang="en"> <head> <title>Sign in to your account</title> <meta http-equiv="... RawContent : HTTP/1.1 200 OK Pragma: no-cache Strict-Transport-Security: max-age=31536000; includeSubDomains X-Content-Type-Options: nosniff X-Frame-Options: DENY Link: <https://aadcdn.msftauth.net>; rel=prec... Forms : {} Headers : {[Pragma, no-cache], [Strict-Transport-Security, max-age=31536000; includeSubDomains], [X-Content-Type-Options, nosniff], [X-Frame-Options, DENY]...} Images : {} InputFields : {} Links : {@{innerHTML=Terms of use; innerText=Terms of use; outerHTML=<a class="footer-content ext-footer-content footer-item ext-footer-item" id="ftrTerms" href="https://www.microsoft.com/en-US/servicesagreement/" data-bind=" text: termsText, href: termsLink, click: termsLink_onClick, externalCss: { 'footer-content': true, 'footer-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }">Terms of use</a>; outerText=Terms of use; tagName=A; class=footer-content ext-footer-content footer-item ext-footer-item; id=ftrTerms; href=https://www.microsoft.com/en-US/servicesagreement/; data-bind= text: termsText, href: termsLink, click: termsLink_onClick, externalCss: { 'footer-content': true, 'footer-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }}, @{innerHTML=Privacy & cookies; innerText=Privacy & cookies; outerHTML=<a class="footer-content ext-footer-content footer-item ext-footer-item" id="ftrPrivacy" href="https://privacy.microsoft.com/en-US/privacystatement" data-bind=" text: privacyText, href: privacyLink, click: privacyLink_onClick, externalCss: { 'footer-content': true, 'footer-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }">Privacy & cookies</a>; outerText=Privacy & cookies; tagName=A; class=footer-content ext-footer-content footer-item ext-footer-item; id=ftrPrivacy; href=https://privacy.microsoft.com/en-US/privacystatement; data-bind= text: privacyText, href: privacyLink, click: privacyLink_onClick, externalCss: { 'footer-content': true, 'footer-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }}, @{innerHTML=...; innerText=...; outerHTML=<a class="footer-content ext-footer-content footer-item ext-footer-item debug-item ext-debug-item" id="moreOptions" role="button" aria-expanded="false" aria-label="Click here for troubleshooting information" href="#" data-bind=" click: moreInfo_onClick, ariaLabel: str['CT_STR_More_Options_Ellipsis_AriaLabel'], attr: { 'aria-expanded': showDebugDetails().toString() }, hasFocusEx: focusMoreInfo(), externalCss: { 'footer-content': true, 'footer-item': true, 'debug-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }">...</a>; outerText=...; tagName=A; class=footer-content ext-footer-content footer-item ext-footer-item debug-item ext-debug-item; id=moreOptions; role=button; aria-expanded=false; aria-label=Click here for troubleshooting information; href=#; data-bind= click: moreInfo_onClick, ariaLabel: str['CT_STR_More_Options_Ellipsis_AriaLabel'], attr: { 'aria-expanded': showDebugDetails().toString() }, hasFocusEx: focusMoreInfo(), externalCss: { 'footer-content': true, 'footer-item': true, 'debug-item': true, 'has-background': !useDefaultBackground, 'background-always-visible': hasDarkBackground }}} ParsedHtml : mshtml.HTMLDocumentClass RawContentLength : 187698
Was kann ich mit den gefundenen Daten jetzt anfangen? Wie kann ich daraus den Ordnerinhalt von "Production" herauslesen?
EDIT: Thread umbenannt, da das Thema sich in eine andere Richtung entwickelt.- Bearbeitet Guido_T Montag, 8. März 2021 10:32 Thread umbenannt, da das Thema sich in eine andere Richtung entwickelt.
Antworten
-
Hi Guido,
bau in den Catch scope einfach nur mal eine einfache Auswertung ein und zeige, was da in log.txt angezeigt wird:}catch { $_.Exception.Message | Out-File $prot -append if ($_.Exception.InnerException.Response){ throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd() }else{ throw $_.Exception.InnerException } }
Ich wette, dass die Url für die WebSite falsch ist:
https://mycompany.sharepoint.com/sites/collection3/sp1/Production
Wenn du diese Url im Browser eingibst, wird da das gewünschte Portal (WebSite) angezeigt?
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks
- Bearbeitet Peter Fleischer Montag, 8. März 2021 12:34
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58
-
Hi Guido,
hier mal ein PowerShell Script mit CSOM. Die beiden erforderlichen dll habe ich in den Unterordner Cloud kopiert.<# SharePoint via CSOM auslesen; alle Dateien anzeigen, incl. Ordner #> Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Cloud\Microsoft.SharePoint.Client.dll" Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Cloud\Microsoft.SharePoint.Client.Runtime.dll" if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return} # ====== Variablen ========= $SiteUrl = "https://xxx.sharepoint.com" $Username = 'xxx@xxx.onmicrosoft.com' $Password = 'xxx' $prot = "c:\temp\log.txt" # ====== ENDE Variablen ==== #Create Credential object from given user name and password $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, (ConvertTo-SecureString $Password -AsPlainText -Force)) #Set up the context $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $Ctx.Credentials = $Cred function Portal() { try{ # Get the Web Object $Web = $Ctx.web $Ctx.Load($Web) $Ctx.ExecuteQuery() "Portal: ServerRelativeUrl: " + $Web.ServerRelativeUrl + " - Title: " + $Web.Title | Out-File $prot -append # Lists / Bibs für Hauptportal ListsBibs($Web) # Subportale SubPortals($Web) }catch { $ex = $_.Exception while($ex -ne $null) { $ex.Message | Out-File $prot -append $ex = $ex.InnerException } throw $_ } } function SubPortals([Microsoft.SharePoint.Client.Web]$web) { $Webs =$Web.Webs $ctx.Load($Webs) $Ctx.ExecuteQuery() ForEach ($item in $Webs) { "SubPortal: ServerRelativeUrl: " + $item.ServerRelativeUrl + " - Title: " + $item.Title | Out-File $prot -append ListsBibs($item) SubPortals($item) } } function ListsBibs([Microsoft.SharePoint.Client.Web]$web) { $Lists = $Web.Lists $ctx.Load($Lists) $Ctx.ExecuteQuery() # Listen / Bibliotheken ForEach ($item in $Lists) { if ($item.BaseTemplate -eq "101") { $listenName = $item.Title " Liste/Bibliothek " + $item.BaseTemplate + " : " + $listenName + " - " + $Web.ServerRelativeUrl + "/" + $listenName | Out-File $prot -append BibFolders $item } } } function BibFolders([Microsoft.SharePoint.Client.List]$ListBib) { BibFiles $ListBib.RootFolder # Subfolders $Folders = $ListBib.RootFolder.Folders $ctx.Load($Folders) $Ctx.ExecuteQuery() ForEach ($item in $Folders) { " Subfolder: " + $item.Name + " - " + $item.ServerRelativeUrl | Out-File $prot -append BibFiles $item } # } } function BibFiles([Microsoft.SharePoint.Client.Folder]$Folder) { $Files = $Folder.Files $ctx.Load($Files) $Ctx.ExecuteQuery() ForEach ($item in $Files) { " Dokument: " + $item.Name | Out-File $prot -append } } "-------- Analyse" | Out-File $prot Portal
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58
-
Hi Guido,
ich habe mir mal die Mühe gemacht, einen PowerShell Script zu schreiben, mit dem aus allen Dokument Bibliotheken incl. der Ordner und Unterordner die Dateien aufgelistet werden (in einer txt Datei), und das mittels REST Api.<# SharePoint via API auslesen; alle Dateien anzeigen, incl. Ordner #> # ====== Variablen ========= $Uri = "http://sps2019.lg.loc" $USERNAME = 'lg\admin' $PASSWORD = 'Passw0rd' $Namespace = @{ns="http://www.w3.org/2005/Atom"; d="http://schemas.microsoft.com/ado/2007/08/dataservices"; m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"} $prot = "c:\temp\log.txt" # ====== ENDE Variablen ==== if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return} # Funktion zum Senden eines WebRequests function Execute-GetRequest { param( [String]$URL ) try{ # Parameter für Anmeldung $nc = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) # Web-Zugriff $wr = [System.Net.WebRequest]::Create($Uri + $URL) $wr.Credentials = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) $wr.Method = 'GET' $wr.Accept = 'application/xml;odata=verbose' $wr.ContentType = "application/xml;odata=verbose" # Antwort vorbereiten [System.Net.HttpWebResponse]$wresp = $wr.GetResponse() # Datenstrom holen $responseStream = $wresp.GetResponseStream() # Reader zuweisen $responseXML = [Xml]([System.IO.StreamReader]($responseStream)).ReadToEnd() $responseStream.Close() return $responseXML }catch { if ($_.Exception.InnerException.Response){ throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd() }else{ throw $_.Exception.InnerException } } } function Portal([String]$reativeUrl = "/") { # root Portal $resultXML = Execute-GetRequest($reativeUrl + "/_api/web") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { "Portal: ServerRelativeUrl: " + $item.Node.ServerRelativeUrl + " - Title: " + $item.Node.Title | Out-File $prot -append ListsBibs($item.Node.ServerRelativeUrl) } # Subportale $resultXML = Execute-GetRequest($reativeUrl + "/_api/site/rootWeb/webinfos") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { "SubPortal: ServerRelativeUrl: " + $item.Node.ServerRelativeUrl + " - Title: " + $item.Node.Title | Out-File $prot -append ListsBibs($item.Node.ServerRelativeUrl) } } function ListsBibs([String]$relativeUrl) { $resultXML = Execute-GetRequest($relativeUrl + "/_api/web/lists") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { if ($item.Node.BaseTemplate.'#text' -eq "101") { $listenName = $item.Node.Title $decodedBibName = [System.Xml.XmlConvert]::DecodeName($item.Node.EntityTypeName) " Liste/Bibliothek " + $item.Node.BaseTemplate.'#text' + " : " + $listenName + " - " + $relativeUrl + "/" + $decodedBibName | Out-File $prot -append BibFolders $relativeUrl $decodedBibName } } } function BibFolders { param([String]$relativeUrl, [String]$bibName) BibFiles $relativeUrl $bibName # Subfolders $resultXML2 = Execute-GetRequest($relativeUrl + "/_api/web/GetFolderByServerRelativeUrl('$bibName')/folders") $result2 = Select-Xml -Xml $resultXML2 -Namespace $Namespace -XPath "//m:properties" ForEach ($item2 in $result2) { " Subfolder: " + $item2.Node.Name + " - " + $item2.Node.ServerRelativeUrl | Out-File $prot -append $newBibName2 = $bibName + "/" + $item2.Node.Name BibFolders $relativeUrl $newBibName2 } # } } function BibFiles { param([String]$relativeUrl, [String]$bibName) $resultXML = Execute-GetRequest($relativeUrl + "/_api/web/GetFolderByServerRelativeUrl('$bibName')/Files") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { " Dokument: " + $item.Node.Name | Out-File $prot -append } } Portal "/doz"
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Bearbeitet Peter Fleischer Sonntag, 7. März 2021 15:13
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58
Alle Antworten
-
Hi Guido,
mit deiner Request-Url greifst du nicht auf die API zu, sondern auf den Seiteninhalt in "collection3". Da du beim Request nichts weiter angegeben hast, wird dir JSon geliefert. Mit ConvertFrom-JSON kannst du dir die Content Eigenschaft holen. Um sinnvolle Ergebnisse zu erreichen, musst du für dein Ziel die API aufrufen (_api).Eine Frage bleibt offen: "Warum nutzt du nicht CSOM für den Zugriff?"
Hier mal ein PowerShell Script für das Auslesen der Titel der Elemente einer Liste:
<# SharePoint via API auslesen #> # ====== Variablen ========= $Uri = "http://sps2019.lg.loc" $USERNAME = 'lg\admin' $PASSWORD = 'Passw0rd' # ====== ENDE Variablen ==== if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return} # Funktion zum Senden eines WebRequests function Execute-GetRequest { param( [String]$URL ) try{ # Parameter für Anmeldung $nc = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) # Web-Zugriff $wr = [System.Net.WebRequest]::Create($Uri + $URL) $wr.Credentials = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) $wr.Method = 'GET' $wr.Accept = 'application/xml;odata=verbose' $wr.ContentType = "application/xml;odata=verbose" # Antwort vorbereiten [System.Net.HttpWebResponse]$wresp = $wr.GetResponse() # Datenstrom holen $responseStream = $wresp.GetResponseStream() # Reader zuweisen $responseXML = [Xml]([System.IO.StreamReader]($responseStream)).ReadToEnd() $responseStream.Close() return $responseXML }catch { if ($_.Exception.InnerException.Response){ throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd() }else{ throw $_.Exception.InnerException } } } $resultXML = Execute-GetRequest("/doz/_api/web/lists/GetByTitle('Liste1')/items") $Namespace = @{d="http://schemas.microsoft.com/ado/2007/08/dataservices"} $result = Select-Xml -Xml $res -Namespace $Namespace -XPath "//d:Title" ForEach ($item in $result) {$item.ToString()}
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks
- Bearbeitet Peter Fleischer Samstag, 6. März 2021 06:21
-
Hi Guido,
ich habe mir mal die Mühe gemacht, einen PowerShell Script zu schreiben, mit dem aus allen Dokument Bibliotheken incl. der Ordner und Unterordner die Dateien aufgelistet werden (in einer txt Datei), und das mittels REST Api.<# SharePoint via API auslesen; alle Dateien anzeigen, incl. Ordner #> # ====== Variablen ========= $Uri = "http://sps2019.lg.loc" $USERNAME = 'lg\admin' $PASSWORD = 'Passw0rd' $Namespace = @{ns="http://www.w3.org/2005/Atom"; d="http://schemas.microsoft.com/ado/2007/08/dataservices"; m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"} $prot = "c:\temp\log.txt" # ====== ENDE Variablen ==== if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return} # Funktion zum Senden eines WebRequests function Execute-GetRequest { param( [String]$URL ) try{ # Parameter für Anmeldung $nc = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) # Web-Zugriff $wr = [System.Net.WebRequest]::Create($Uri + $URL) $wr.Credentials = [System.Net.NetworkCredential]::new($USERNAME,$PASSWORD) $wr.Method = 'GET' $wr.Accept = 'application/xml;odata=verbose' $wr.ContentType = "application/xml;odata=verbose" # Antwort vorbereiten [System.Net.HttpWebResponse]$wresp = $wr.GetResponse() # Datenstrom holen $responseStream = $wresp.GetResponseStream() # Reader zuweisen $responseXML = [Xml]([System.IO.StreamReader]($responseStream)).ReadToEnd() $responseStream.Close() return $responseXML }catch { if ($_.Exception.InnerException.Response){ throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd() }else{ throw $_.Exception.InnerException } } } function Portal([String]$reativeUrl = "/") { # root Portal $resultXML = Execute-GetRequest($reativeUrl + "/_api/web") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { "Portal: ServerRelativeUrl: " + $item.Node.ServerRelativeUrl + " - Title: " + $item.Node.Title | Out-File $prot -append ListsBibs($item.Node.ServerRelativeUrl) } # Subportale $resultXML = Execute-GetRequest($reativeUrl + "/_api/site/rootWeb/webinfos") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { "SubPortal: ServerRelativeUrl: " + $item.Node.ServerRelativeUrl + " - Title: " + $item.Node.Title | Out-File $prot -append ListsBibs($item.Node.ServerRelativeUrl) } } function ListsBibs([String]$relativeUrl) { $resultXML = Execute-GetRequest($relativeUrl + "/_api/web/lists") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { if ($item.Node.BaseTemplate.'#text' -eq "101") { $listenName = $item.Node.Title $decodedBibName = [System.Xml.XmlConvert]::DecodeName($item.Node.EntityTypeName) " Liste/Bibliothek " + $item.Node.BaseTemplate.'#text' + " : " + $listenName + " - " + $relativeUrl + "/" + $decodedBibName | Out-File $prot -append BibFolders $relativeUrl $decodedBibName } } } function BibFolders { param([String]$relativeUrl, [String]$bibName) BibFiles $relativeUrl $bibName # Subfolders $resultXML2 = Execute-GetRequest($relativeUrl + "/_api/web/GetFolderByServerRelativeUrl('$bibName')/folders") $result2 = Select-Xml -Xml $resultXML2 -Namespace $Namespace -XPath "//m:properties" ForEach ($item2 in $result2) { " Subfolder: " + $item2.Node.Name + " - " + $item2.Node.ServerRelativeUrl | Out-File $prot -append $newBibName2 = $bibName + "/" + $item2.Node.Name BibFolders $relativeUrl $newBibName2 } # } } function BibFiles { param([String]$relativeUrl, [String]$bibName) $resultXML = Execute-GetRequest($relativeUrl + "/_api/web/GetFolderByServerRelativeUrl('$bibName')/Files") $result = Select-Xml -Xml $resultXML -Namespace $Namespace -XPath "//m:properties" ForEach ($item in $result) { " Dokument: " + $item.Node.Name | Out-File $prot -append } } Portal "/doz"
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Bearbeitet Peter Fleischer Sonntag, 7. März 2021 15:13
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58
-
Wow, vielen Dank für die Mühe. Ich werde das definitiv schnellstmöglich testen.
"Warum nutzt du nicht CSOM für den Zugriff?"
Den Begriff höre ich leider gerade zum ersten mal. Beim Googeln und Bingen taucht im Zusammenhang mit dem Zugriff zum Sharepoint immer in erster Linie die REST-Api auf. In Verbindung damit bin ich jetzt sogar auf eine sehr hilfreiche Seite gestoßen, die ich mal für die Nachwelt hier hinterlassen möchte:
https://docs.microsoft.com/en-us/sharepoint/dev/general-development/choose-the-right-api-set-in-sharepoint
CSOM taucht aber auch hier nicht auf (?)... Ich werde mich zu CSOM allerdings noch einmal belesen.
Eine Frage anbei: Ist es möglich, in PowerShell die aktuellen Nutzer-Credentials auszulesen, ohne diese noch einmal eingeben zu müssen?
Mein Ziel (Pseudocode):
$AD = New-Object System.DirectoryServices.DirectorySearcher $AD.Filter = "cn=$env:USERNAME" $UserMail= $AD.FindOne().Properties.mail #Ab hier PSEUDO-CODE! #Windows-Credentials auslesen $WindowsCredentials = $PSEUDOcmdlet-Get-WinCredential $WebCredentials = $WindowsCredentials #Windows-Nutzername durch E-Mail ersetzen, Passwort bleibt bestehen $WebCredentials.UserName = $UserMail
-
Hi Guido,
die Credentials von Nutzern auszulesen, funktioniert glücklicherweise nicht. Wenn das funktionieren würde, dann wären alle Anstrengungen zur Gewährleistung der Sicherheit sinnlos, da es damit keine Sicherheit gäbe.Der SharePoint ist optimal konzipiert für ein Hol-Prinzip, d.h., jeder Anwender entscheidet, was er sehen will, bzw. worüber er informiert werden will. Bei dieser Arbeitsweise ist es nicht notwendig, dass Nutzernamen, Kennworte usw. von anderen Anwendern bekannt sein müssen.
Deshalb bleibt die Frage: "Wozu benötigst du die Sicherheitsinformation anderer Nutzer?".
Wo informierst du dich über die API's in SharePoint?
Index für SharePoint .NET Server, CSOM, JSOM und REST-API | Microsoft Docs
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks -
Die Nutzerinformationen benötige ich ja nur von dem am aktuellen PC angemeldeten Nutzer. Bspw. Max Muster mit der Kennung "mmuster" geht an seinen PC und führt ein Script aus, mit welchem er ein Verzeichnis im SharePoint durchsuchen möchte (wofür er allerdings die E-Mail "m.muster@firma.com" benötigt). Damit er jedoch nicht bei jeder Script-Ausführung seine Daten eingeben muss, müsste das Script diese entweder bei der erstmaligen Eingabe in einer Datei ablegen (sehr unsicher) oder im Idealfall eben aus der aktuellen User-Session auslesen. Es gibt eine Reihe von proprietären Programmen, die bspw. mittels SSO o.ä. in der Lage sind, die aktuellen Nutzerdaten zu verwenden um eine Serveranmeldung durchzuführen. Dort klappt es doch auch irgendwie?
Zum Thema CSOM teste ich gerade ein wenig herum. Da es sich ja nicht mehr um REST handelt, sollte ich dafür einen neuen Thread aufmachen oder sollte man diesen hier umbenennen?
-
Hi Guido,
wenn basic forms authentication mit Nutzername und Kennwort eingestellt ist und single sign on genutzt wird, dann reicht dafür CredentialCache.DefaultCredentials.--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks -
Ich habe den Thread umbenannt.
Leider kommt bei dem REST-Beispiel immer ein TimeOut. Ich habe den Code abgewandelt zu
$PASSWORD = ConvertTo-SecureString 'MeinPasswort' -AsPlainText -Force
aber leider ohne Erfolg. Vermutlich mache ich an anderer Stelle etwas falsch?
$Uri = "https://mycompany.sharepoint.com" (...) Portal "https://mycompany.sharepoint.com/sites/collection3/sp1/Production" #->TimeOut
Portal "/sites/collection3/sp1/Production" #->TimeOut
Zu CSOM: Dazu finden sich glücklicherweise einige Samples im Internet für PowerShell, allerdings tritt bei mir ein Fehler auf, den ich mit den Tutorials nicht nachvollziehen kann.
Der Namespace Microsoft.SharePoint erscheint bei mir auch gar nicht... Das SharePoint Online SDK habe ich allerdings installiert (Quelle https://www.microsoft.com/en-us/download/details.aspx?id=42038).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" $URL = "https://mycompany.sharepoint.com/sites/collection3/sp1/Production" $CTX = New-Object Microsoft.SharePoint.Client.ClientContext($URL) if ($Credential -eq $null) {$Credential = get-credential "MeineEmail@firma.com"} $CTX.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Credential.UserName, $Credential.Password) $CTX.Load($CTX.Web) $CTX.ExecuteQuery()
$CTX.Web
format-default : The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
+ CategoryInfo : NotSpecified: (:) [format-default], CollectionNotInitializedException
+ FullyQualifiedErrorId : Microsoft.SharePoint.Client.CollectionNotInitializedException,Microsoft.PowerShell.Commands.FormatDefaultCommand -
Hi Guido,
wenn ein Time Out kommt, dann kann mit der Url nicht zugegriffen werden. Ursache dafür können eine falsche Url, Blockierungen durch firewall oder auch fehlende Rechte im SharePoint sein. Das solltest du untersuchen. Vielleicht ist irgendwo ein kleiner Vertipper. Funktioniert denn die Url aus dem Browser mit den gleichen Kontoangaben? Hast du es mal mit ausgeschalteten firewalls getestet?Bevor du im Script etwas änderst, solltest du den Script unverändert starten (lediglich Url, Nutzername, Kennwort fest eintragen). Wenn das funktioniert, dann solltest du schrittweise umbauen (z.B. dein ConvertTo-SecureString).
Ich empfehle dir, sich für eine Technologie zu entscheiden und erst einmal dabei zu bleiben.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks -
Ich habe festgestellt, dass ich ein "/" vergessen habe beim aufrufen von Portal().
Der Timeout ist also weg. Allerdings kommt eine andere Fehlermeldung:
$Uri = "https://mycompany.sharepoint.com" $USERNAME = "meineemail@firma.com" $PASSWORD = "Passwort" #(...) Portal "/sites/collection3/sp1/Production" In Zeile:39 Zeichen:13 + throw ([System.IO.StreamReader]($_.Exception.InnerExcepti ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (:String) [], RuntimeException + FullyQualifiedErrorId :
Zeile 39 = throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd()
Wenn ich mit dem Debugger Schritt für Schritt durchgehe bricht er ab bei...Angehalten bei: [System.Net.HttpWebResponse] $wresp = $wr.GetResponse() Angehalten bei: if ($_.Exception.InnerException.Response){
An der Firewall kann ich leider keine Änderungen vornehmen. Diese wird von der Konzern-IT verwaltet. Wenn du mir jedoch konkrete Ports benennen kannst, kann ich deren Freigabe beantragen.
Zum Thema Technologie: Mein Endziel lautet, Dokumente aus dem SharePoint heraus direkt aufrufen zu können, ohne dass sich der Nutzer mittels Webbrowser durch die ganzen Bibliotheken kämpfen muss. Ob dies letzten Endes mittels REST oder CSOM geschieht, ist mir prinzipiell egal. Da ich allerdings nicht tagtäglich in den Quellcodes herumwühlen werde, sollte es natürlich etwas "anfängertaugliches" sein was nach Möglichkeit viele Schritte automatisch ausführt und ohne diverse Umwege über zusätzliche Parser und Converter (falls dies geht).
Hier bin ich also ganz auf deine Expertise angewiesen, da du davon ja einiges zu verstehen scheinst. ;-)
- Bearbeitet Guido_T Montag, 8. März 2021 12:10
-
Hi Guido,
bau in den Catch scope einfach nur mal eine einfache Auswertung ein und zeige, was da in log.txt angezeigt wird:}catch { $_.Exception.Message | Out-File $prot -append if ($_.Exception.InnerException.Response){ throw ([System.IO.StreamReader]($_.Exception.InnerException.Response.GetResponseStream())).ReadToEnd() }else{ throw $_.Exception.InnerException } }
Ich wette, dass die Url für die WebSite falsch ist:
https://mycompany.sharepoint.com/sites/collection3/sp1/Production
Wenn du diese Url im Browser eingibst, wird da das gewünschte Portal (WebSite) angezeigt?
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks
- Bearbeitet Peter Fleischer Montag, 8. März 2021 12:34
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58
-
log.txt:
Ausnahme beim Aufrufen von "GetResponse" mit 0 Argument(en): "Der Remoteserver hat einen Fehler zurückgegeben: (404) Nicht gefunden."
Ja, die Original-URL funktioniert im Browser.
Beim Debuggen ist mir jedoch auch aufgefallen, dass die Zeile
$wr = [System.Net.WebRequest]::Create($Uri + $URL)
auf folgende URL hinausläuft: https://mycompany.sharepoint.com/sites/collection3/sp1/Production/_api/web
Kann man denn /_api/web von jedem Sharepoint-Verzeichnis aus aufrufen?
Ich habe die letzte Zeile im Script abgewandelt zu:
Portal "/sites/collection3/sp1"
Nun lautet die Fehlermeldung:<?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code>-2147024891, System.UnauthorizedAccessException</m:code><m:message xml:lang="en-US">Access
denied. You do not have permission to perform this action or access this resource.</m:message></m:error>
In Zeile:43 Zeichen:13
+ throw ([System.IO.StreamReader]($_.Exception.InnerExcepti ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (<?xml version="...sage></m:error>:String) [], RuntimeException
+ FullyQualifiedErrorId : <?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code>-2147024891, System.UnauthorizedAccessException</m:code><m:messa
ge xml:lang="en-US">Access denied. You do not have permission to perform this action or access this resource.</m:message></m:error>
log.txt:
Ausnahme beim Aufrufen von "GetResponse" mit 0 Argument(en): "Der Remoteserver hat einen Fehler zurückgegeben: (403) Unzulässig."
Im besagten SharePoint habe ich allerdings Owner-Rechte.
-
Hi Guido,
wenn der Server mit 404 antwortet, dann ist die URL falsch. In deinem Fall hat er unter der Websitesammling "https://mycompany.sharepoint.com/sites/collection3" das Subweb "sp1" und darunter das Subweb "Production" nicht gefunden. Das Script soll dann in diesem Subweb "Produktion" die Bibliotheken auflisten. Dazu muss aber das Subweb auch vorhanden sein. Und das scheint mir bei dir nicht der Fall zu sein.Im dem Subweb "Production" übergeordneten Subweb "sp1" hast du keinen Zugriff mit dem genutzten Konto.
Du solltest erst einmal genau überlegen, was du willst, dann ggf. erst einmal mit einem ausreichend berechtigten Konto testen.
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks -
Hi Guido,
hier mal ein PowerShell Script mit CSOM. Die beiden erforderlichen dll habe ich in den Unterordner Cloud kopiert.<# SharePoint via CSOM auslesen; alle Dateien anzeigen, incl. Ordner #> Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Cloud\Microsoft.SharePoint.Client.dll" Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Cloud\Microsoft.SharePoint.Client.Runtime.dll" if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return} # ====== Variablen ========= $SiteUrl = "https://xxx.sharepoint.com" $Username = 'xxx@xxx.onmicrosoft.com' $Password = 'xxx' $prot = "c:\temp\log.txt" # ====== ENDE Variablen ==== #Create Credential object from given user name and password $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, (ConvertTo-SecureString $Password -AsPlainText -Force)) #Set up the context $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl) $Ctx.Credentials = $Cred function Portal() { try{ # Get the Web Object $Web = $Ctx.web $Ctx.Load($Web) $Ctx.ExecuteQuery() "Portal: ServerRelativeUrl: " + $Web.ServerRelativeUrl + " - Title: " + $Web.Title | Out-File $prot -append # Lists / Bibs für Hauptportal ListsBibs($Web) # Subportale SubPortals($Web) }catch { $ex = $_.Exception while($ex -ne $null) { $ex.Message | Out-File $prot -append $ex = $ex.InnerException } throw $_ } } function SubPortals([Microsoft.SharePoint.Client.Web]$web) { $Webs =$Web.Webs $ctx.Load($Webs) $Ctx.ExecuteQuery() ForEach ($item in $Webs) { "SubPortal: ServerRelativeUrl: " + $item.ServerRelativeUrl + " - Title: " + $item.Title | Out-File $prot -append ListsBibs($item) SubPortals($item) } } function ListsBibs([Microsoft.SharePoint.Client.Web]$web) { $Lists = $Web.Lists $ctx.Load($Lists) $Ctx.ExecuteQuery() # Listen / Bibliotheken ForEach ($item in $Lists) { if ($item.BaseTemplate -eq "101") { $listenName = $item.Title " Liste/Bibliothek " + $item.BaseTemplate + " : " + $listenName + " - " + $Web.ServerRelativeUrl + "/" + $listenName | Out-File $prot -append BibFolders $item } } } function BibFolders([Microsoft.SharePoint.Client.List]$ListBib) { BibFiles $ListBib.RootFolder # Subfolders $Folders = $ListBib.RootFolder.Folders $ctx.Load($Folders) $Ctx.ExecuteQuery() ForEach ($item in $Folders) { " Subfolder: " + $item.Name + " - " + $item.ServerRelativeUrl | Out-File $prot -append BibFiles $item } # } } function BibFiles([Microsoft.SharePoint.Client.Folder]$Folder) { $Files = $Folder.Files $ctx.Load($Files) $Ctx.ExecuteQuery() ForEach ($item in $Files) { " Dokument: " + $item.Name | Out-File $prot -append } } "-------- Analyse" | Out-File $prot Portal
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 15. März 2021 11:15
- Als Antwort markiert Ivan DragovMicrosoft contingent staff, Moderator Mittwoch, 31. März 2021 09:58