int main(void) { wchar_t buf[1024]; _invalid_parameter_handler oldHandler, newHandler; newHandler = invalidParameterHandler; oldHandler = _set_invalid_parameter_handler(newHandler); // Disable the message box for assertions when linked with debug CRT library. _CrtSetReportMode(_CRT_ASSERT, 0); if (_setmode(_fileno(stdin), _O_U8TEXT) == -1) { perror("Cannot set stdin to UTF-8"); exit(1); } if (_setmode(_fileno(stdout), _O_U16TEXT) == -1) { perror("Cannot set stdout to Unicode"); exit(1); } while (_getws(buf)) { if (wcschr(buf, L'\xfffd')) { fprintf(stderr, "Error: Input stream not in UTF-8\n"); exit(1); } _putws(buf); } }
//---------------------------------------------------------------------------- // // EnumDeletedObjects() // // Enumerates all of the objects in the Deleted Objects container. // //---------------------------------------------------------------------------- HRESULT EnumDeletedObjects( PWCHAR SearchFilter, BOOLEAN Restore, PDWORD ItemsFound ) { HRESULT hr; IADsContainer *pDeletedObjectsCont = NULL; IDirectorySearch *pSearch = NULL; // Set the attributes to retrieve. LPWSTR rgAttributes[] = {L"cn", L"distinguishedName", L"lastKnownParent"}; *ItemsFound = 0; hr = GetDeletedObjectsContainer(&pDeletedObjectsCont); if(FAILED(hr)) { goto cleanup; } hr = pDeletedObjectsCont->QueryInterface(IID_IDirectorySearch, (LPVOID*)&pSearch); if(FAILED(hr)) { goto cleanup; } ADS_SEARCH_HANDLE hSearch; // Only search for direct children of the container. ADS_SEARCHPREF_INFO rgSearchPrefs[3]; rgSearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; rgSearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER; rgSearchPrefs[0].vValue.Integer = ADS_SCOPE_ONELEVEL; // Search for deleted objects. rgSearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_TOMBSTONE; rgSearchPrefs[1].vValue.dwType = ADSTYPE_BOOLEAN; rgSearchPrefs[1].vValue.Boolean = TRUE; // Set the page size. rgSearchPrefs[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; rgSearchPrefs[2].vValue.dwType = ADSTYPE_INTEGER; rgSearchPrefs[2].vValue.Integer = 1000; // Set the search preference hr = pSearch->SetSearchPreference(rgSearchPrefs, ARRAYSIZE(rgSearchPrefs)); if(FAILED(hr)) { goto cleanup; } // Execute the search hr = pSearch->ExecuteSearch( SearchFilter, rgAttributes, ARRAYSIZE(rgAttributes), &hSearch); if(SUCCEEDED(hr)) { // Call IDirectorySearch::GetNextRow() to retrieve the next row of data while(S_OK == (hr = pSearch->GetNextRow(hSearch))) { ADS_SEARCH_COLUMN col; UINT i; // Enumerate the retrieved attributes. for(i = 0; i < ARRAYSIZE(rgAttributes); i++) { hr = pSearch->GetColumn(hSearch, rgAttributes[i], &col); if(SUCCEEDED(hr)) { switch(col.dwADsType) { case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_DN_STRING: case ADSTYPE_PRINTABLE_STRING: case ADSTYPE_NUMERIC_STRING: case ADSTYPE_OCTET_STRING: wprintf(L"%s: ", rgAttributes[i]); for(DWORD x = 0; x < col.dwNumValues; x++) { wprintf(col.pADsValues[x].CaseIgnoreString); if((x + 1) < col.dwNumValues) { wprintf(L","); } } wprintf(L"\n"); break; } pSearch->FreeColumn(&col); } } (*ItemsFound)++; wprintf(L"\n"); if( Restore ) { WCHAR answer[MAX_PATH]; wprintf(L"Do you want to restore this object (y/n)? "); fflush( stdout ); _getws( answer ); if( towupper( answer[0] ) == 'Y' ) { ADS_SEARCH_COLUMN colDn, colPn; pSearch->GetColumn(hSearch, rgAttributes[1], &colDn); pSearch->GetColumn(hSearch, rgAttributes[2], &colPn); hr = RestoreDeletedObject( colDn.pADsValues[0].CaseIgnoreString, colPn.pADsValues[0].CaseIgnoreString ); if( FAILED( hr )) { wprintf(L"\nRestore failed: %d\n", hr ); } else { wprintf(L"\nRestore succeeded.\n"); } pSearch->FreeColumn(&colDn); pSearch->FreeColumn(&colPn); } wprintf(L"\n"); } } // Close the search handle to clean up. pSearch->CloseSearchHandle(hSearch); } cleanup: if(pDeletedObjectsCont) { pDeletedObjectsCont->Release(); } if(pSearch) { pSearch->Release(); } return hr; }